@angular-generic-table/core 5.0.0-rc.2 → 5.0.0-rc.20

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 (76) hide show
  1. package/esm2020/angular-generic-table-core.mjs +5 -0
  2. package/esm2020/lib/core.component.mjs +560 -0
  3. package/esm2020/lib/core.module.mjs +47 -0
  4. package/esm2020/lib/core.service.mjs +14 -0
  5. package/esm2020/lib/gt-delta/gt-delta.component.mjs +126 -0
  6. package/esm2020/lib/models/gt-pagination.mjs +2 -0
  7. package/esm2020/lib/models/table-column.interface.mjs +2 -0
  8. package/esm2020/lib/models/table-config.interface.mjs +2 -0
  9. package/esm2020/lib/models/table-events.interface.mjs +2 -0
  10. package/esm2020/lib/models/table-info.interface.mjs +2 -0
  11. package/esm2020/lib/models/table-meta.interface.mjs +2 -0
  12. package/esm2020/lib/models/table-row.interface.mjs +2 -0
  13. package/esm2020/lib/models/table-sort.interface.mjs +2 -0
  14. package/esm2020/lib/pagination/pagination.component.mjs +157 -0
  15. package/esm2020/lib/pagination/pagination.module.mjs +17 -0
  16. package/esm2020/lib/pipes/capital-case.pipe.mjs +18 -0
  17. package/esm2020/lib/pipes/dash-case.pipe.mjs +18 -0
  18. package/esm2020/lib/pipes/dynamic.pipe.mjs +26 -0
  19. package/esm2020/lib/pipes/highlight.pipe.mjs +49 -0
  20. package/esm2020/lib/pipes/row-selection.pipe.mjs +17 -0
  21. package/esm2020/lib/pipes/sort-class.pipe.mjs +40 -0
  22. package/esm2020/lib/utilities/utilities.mjs +186 -0
  23. package/esm2020/public-api.mjs +24 -0
  24. package/fesm2015/angular-generic-table-core.mjs +1253 -0
  25. package/fesm2015/angular-generic-table-core.mjs.map +1 -0
  26. package/fesm2020/angular-generic-table-core.mjs +1240 -0
  27. package/fesm2020/angular-generic-table-core.mjs.map +1 -0
  28. package/index.d.ts +5 -0
  29. package/lib/core.component.d.ts +123 -18
  30. package/lib/core.module.d.ts +13 -0
  31. package/lib/core.service.d.ts +3 -0
  32. package/lib/gt-delta/gt-delta.component.d.ts +32 -0
  33. package/lib/models/gt-pagination.d.ts +18 -0
  34. package/lib/models/table-column.interface.d.ts +15 -3
  35. package/lib/models/table-config.interface.d.ts +44 -6
  36. package/lib/models/table-events.interface.d.ts +27 -0
  37. package/lib/models/table-info.interface.d.ts +3 -1
  38. package/lib/models/table-meta.interface.d.ts +8 -0
  39. package/lib/models/table-row.interface.d.ts +1 -1
  40. package/lib/models/table-sort.interface.d.ts +6 -4
  41. package/lib/pagination/pagination.component.d.ts +62 -0
  42. package/lib/pagination/pagination.module.d.ts +8 -0
  43. package/lib/pipes/capital-case.pipe.d.ts +7 -0
  44. package/lib/pipes/dash-case.pipe.d.ts +3 -0
  45. package/lib/pipes/dynamic.pipe.d.ts +9 -0
  46. package/lib/pipes/highlight.pipe.d.ts +3 -0
  47. package/lib/pipes/row-selection.pipe.d.ts +8 -0
  48. package/lib/pipes/sort-class.pipe.d.ts +5 -5
  49. package/lib/utilities/utilities.d.ts +32 -0
  50. package/package.json +22 -10
  51. package/public-api.d.ts +12 -0
  52. package/scss/index.scss +319 -0
  53. package/angular-generic-table-core.d.ts +0 -7
  54. package/angular-generic-table-core.metadata.json +0 -1
  55. package/bundles/angular-generic-table-core.umd.js +0 -594
  56. package/bundles/angular-generic-table-core.umd.js.map +0 -1
  57. package/bundles/angular-generic-table-core.umd.min.js +0 -2
  58. package/bundles/angular-generic-table-core.umd.min.js.map +0 -1
  59. package/esm2015/angular-generic-table-core.js +0 -8
  60. package/esm2015/lib/core.component.js +0 -107
  61. package/esm2015/lib/core.module.js +0 -16
  62. package/esm2015/lib/core.service.js +0 -13
  63. package/esm2015/lib/enums/order.enum.js +0 -6
  64. package/esm2015/lib/models/table-column.interface.js +0 -2
  65. package/esm2015/lib/models/table-config.interface.js +0 -2
  66. package/esm2015/lib/models/table-info.interface.js +0 -2
  67. package/esm2015/lib/models/table-row.interface.js +0 -2
  68. package/esm2015/lib/models/table-sort.interface.js +0 -2
  69. package/esm2015/lib/pipes/dash-case.pipe.js +0 -13
  70. package/esm2015/lib/pipes/highlight.pipe.js +0 -44
  71. package/esm2015/lib/pipes/sort-class.pipe.js +0 -12
  72. package/esm2015/lib/utilities/utilities.js +0 -25
  73. package/esm2015/public-api.js +0 -12
  74. package/fesm2015/angular-generic-table-core.js +0 -234
  75. package/fesm2015/angular-generic-table-core.js.map +0 -1
  76. package/lib/enums/order.enum.d.ts +0 -4
@@ -0,0 +1,1240 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, Pipe, Injector, EventEmitter, Component, ChangeDetectionStrategy, Input, Output, NgModule } from '@angular/core';
3
+ import { Subject, ReplaySubject, BehaviorSubject, isObservable, of, combineLatest, fromEvent } from 'rxjs';
4
+ import * as i1 from '@angular/common';
5
+ import { KeyValuePipe, AsyncPipe, NgTemplateOutlet, SlicePipe, NgClass, NgIf, NgForOf, PercentPipe, CommonModule } from '@angular/common';
6
+ import { distinctUntilChanged, tap, shareReplay, startWith, map, switchMap, withLatestFrom, filter, pluck, take, takeUntil } from 'rxjs/operators';
7
+
8
+ class CoreService {
9
+ constructor() { }
10
+ }
11
+ CoreService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: CoreService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
12
+ CoreService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: CoreService, providedIn: 'root' });
13
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: CoreService, decorators: [{
14
+ type: Injectable,
15
+ args: [{
16
+ providedIn: 'root',
17
+ }]
18
+ }], ctorParameters: function () { return []; } });
19
+
20
+ let dashed;
21
+ dashed = (s) => s.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase());
22
+ let capitalize;
23
+ capitalize = (s) => (s.charAt(0).toUpperCase() + s.slice(1))
24
+ .replace(/_/g, ' ')
25
+ .replace(/([A-Z][a-z]+)/g, ' $1')
26
+ .replace(/([A-Z]{2,})/g, ' $1')
27
+ .replace(/\s{2,}/g, ' ')
28
+ .trim();
29
+ let chunk;
30
+ chunk = (array, chunkSize) => {
31
+ if (chunkSize < 0) {
32
+ throw new Error('Invalid chunk size');
33
+ }
34
+ if (chunkSize === 0 && !chunkSize) {
35
+ return [array];
36
+ }
37
+ const CHUNK = [];
38
+ for (let i = 0, len = array.length; i < len; i += chunkSize) {
39
+ CHUNK.push(array.slice(i, i + chunkSize));
40
+ }
41
+ return CHUNK;
42
+ };
43
+ let search;
44
+ search = (text, caseSensitive, data, config) => {
45
+ if (config.columns) {
46
+ const searchColumns = Object.keys(config.columns).filter(
47
+ // @ts-ignore
48
+ (key) => config.columns &&
49
+ !config.columns[key]?.hidden &&
50
+ config.columns[key]?.search !== false);
51
+ const FILTERED = [];
52
+ for (let i = 0; i < data.length; i++) {
53
+ const row = data[i];
54
+ const match = Object.entries(row)
55
+ .filter(([key, value]) => searchColumns.indexOf(key) !== -1)
56
+ .reduce((acc, [key, value], index) => {
57
+ const search = config?.columns[key]?.search;
58
+ // if search is a function...
59
+ if (typeof search === 'function') {
60
+ // ...use search function to return value to search
61
+ value = search(row, key, value);
62
+ }
63
+ return (acc +
64
+ (index === 0 ? '' : ' ? ') +
65
+ (caseSensitive ? value + '' : (value + '').toLowerCase()));
66
+ }, '')
67
+ .indexOf(caseSensitive ? text : text.toLowerCase()) !== -1;
68
+ if (match) {
69
+ FILTERED[FILTERED.length] = row;
70
+ }
71
+ }
72
+ return FILTERED;
73
+ }
74
+ else {
75
+ return data;
76
+ }
77
+ };
78
+ let calculate = (data, config) => {
79
+ const CALCULATIONS = {};
80
+ const COLUMN_CALCULATIONS = {};
81
+ let CALCULATED = Object.entries(config.footer?.columns || {})
82
+ .filter(([columnName, calculations]) => Object.values(calculations || {}).filter((value) => value !== false)
83
+ .length >= 0)
84
+ .reduce((acc, [columnName, calculations], index) => {
85
+ acc[columnName] = Object.entries(calculations || {})
86
+ .filter(([calculation, value]) => value !== false)
87
+ .reduce((acc, [calculation, value]) => {
88
+ if (COLUMN_CALCULATIONS[columnName]) {
89
+ COLUMN_CALCULATIONS[columnName].push(calculation);
90
+ }
91
+ else if (value === true) {
92
+ COLUMN_CALCULATIONS[columnName] = [calculation];
93
+ }
94
+ CALCULATIONS[calculation] = true;
95
+ if (typeof value === 'function') {
96
+ value = value(data, columnName);
97
+ }
98
+ acc[calculation] = value === true ? 0 : value;
99
+ return acc;
100
+ }, {});
101
+ return acc;
102
+ }, {});
103
+ if (Object.keys(CALCULATED).length > 0) {
104
+ for (let i = 0; i < data.length; i++) {
105
+ Object.entries(COLUMN_CALCULATIONS).forEach(([column, calculations]) => {
106
+ if (calculations.indexOf('sum') > -1) {
107
+ CALCULATED[column].sum += data[i][column];
108
+ }
109
+ if (calculations.indexOf('avg') > -1 &&
110
+ calculations.indexOf('sum') === -1) {
111
+ if (CALCULATED[column].sum === undefined) {
112
+ CALCULATED[column].sum = 0;
113
+ }
114
+ CALCULATED[column].sum += data[i][column];
115
+ }
116
+ if (calculations.indexOf('max') > -1 &&
117
+ (!CALCULATED[column].max || +data[i][column] > CALCULATED[column].max)) {
118
+ CALCULATED[column].max = +data[i][column];
119
+ }
120
+ if (calculations.indexOf('min') > -1 &&
121
+ (!CALCULATED[column].min || +data[i][column] < CALCULATED[column].min)) {
122
+ CALCULATED[column].min = +data[i][column];
123
+ }
124
+ });
125
+ }
126
+ Object.entries(COLUMN_CALCULATIONS).forEach(([column, calculations]) => {
127
+ if (calculations.indexOf('avg') !== -1) {
128
+ CALCULATED[column].avg = CALCULATED[column]?.sum / data.length;
129
+ // if sum is not part of calculations config...
130
+ if (calculations.indexOf('sum') === -1 && CALCULATED[column].sum) {
131
+ // ...remove it
132
+ delete CALCULATED[column].sum;
133
+ }
134
+ }
135
+ if (calculations.indexOf('count') !== -1) {
136
+ CALCULATED[column].count = data.length;
137
+ }
138
+ });
139
+ }
140
+ return {
141
+ calculated: CALCULATED,
142
+ calculations: Object.keys(CALCULATIONS).sort((a, b) => (config.footer?.rowOrder?.indexOf(a) || 0) -
143
+ (config.footer?.rowOrder?.indexOf(b) || 0)),
144
+ calculatedColumnsCount: Object.keys(CALCULATED).length || 0,
145
+ };
146
+ };
147
+ /** sortOnMultipleKeys
148
+ * @description Sort data on multiple keys
149
+ * @param {GtSortOrder} keys - array with sort config objects to sort on, data will be sorted according to array order
150
+ * @returns sort function
151
+ */
152
+ const sortOnMultipleKeys = (keys) => {
153
+ const order = keys.map((key) => (key.order === 'desc' ? -1 : 1));
154
+ return (a, b) => {
155
+ for (let i = 0; i < keys.length; i++) {
156
+ const o = keys[i].key;
157
+ if (a[o] === b[o])
158
+ return 0;
159
+ if (a[o] === null)
160
+ return 1;
161
+ if (b[o] === null)
162
+ return -1;
163
+ if (a[o] > b[o])
164
+ return order[i];
165
+ if (a[o] < b[o])
166
+ return -order[i];
167
+ }
168
+ return 0;
169
+ };
170
+ };
171
+ /** parseSortOrderParams
172
+ * @description Convert sort order query param to array with sort config objects
173
+ * @param sortParams - Query param string where each sort config object is separated by comma and order is indicated by + (ascending) or - (descending), e.g. _'name,-age'_
174
+ * @returns GtSortOrder - Array with sort config objects
175
+ */
176
+ const parseSortOrderParams = (sortParams) => {
177
+ const sortParamsArray = sortParams.split(',');
178
+ return sortParamsArray.map((sortParam) => {
179
+ const [key, order] = sortParam.split(':');
180
+ return {
181
+ key: key.replace(/^[+-]/, ''),
182
+ order: order === 'desc' ? 'desc' : 'asc',
183
+ };
184
+ });
185
+ };
186
+ /** sortOrderConfigToParam
187
+ * @description Convert sort config object to string that can be used as query param when sorting is implemented server side
188
+ * @param sortConfig - Sort config object
189
+ * @returns string - Query param string where order is indicated by + (ascending) or - (descending), e.g. _'-name'_
190
+ */
191
+ const sortOrderConfigToParam = (sortConfig) => {
192
+ const order = sortConfig.order === 'desc' ? '-' : '+';
193
+ return `${order}${sortConfig.key}`;
194
+ };
195
+ /** sortOrderToParams
196
+ * @description Convert sort order array to string that can be used as query param when sorting is implemented server side
197
+ * @param sortOrder - Array with sort config objects
198
+ * @returns string - Query param string where each sort config object is separated by comma and order is indicated by + (ascending) or - (descending), e.g. _'name,-age'_
199
+ */
200
+ const sortOrderToParams = (sortOrder) => {
201
+ return sortOrder
202
+ .map((sortConfig) => sortOrderConfigToParam(sortConfig))
203
+ .join(',');
204
+ };
205
+
206
+ class CapitalCasePipe {
207
+ transform(s) {
208
+ return capitalize(s);
209
+ }
210
+ }
211
+ CapitalCasePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: CapitalCasePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
212
+ CapitalCasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.1.1", ngImport: i0, type: CapitalCasePipe, isStandalone: true, name: "capitalCase" });
213
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: CapitalCasePipe, decorators: [{
214
+ type: Pipe,
215
+ args: [{
216
+ name: 'capitalCase',
217
+ standalone: true,
218
+ }]
219
+ }] });
220
+
221
+ class SortClassPipe {
222
+ transform(sortOrder, key, context = 'class') {
223
+ const sortIndex = sortOrder
224
+ ? sortOrder.findIndex((s) => s.key === key)
225
+ : -1;
226
+ if (context === 'aria') {
227
+ if (sortIndex === -1 || !sortOrder) {
228
+ return null;
229
+ }
230
+ else {
231
+ return `${sortOrder[sortIndex].order}ending`;
232
+ }
233
+ }
234
+ else if (context === 'class') {
235
+ if (sortIndex === -1 || !sortOrder) {
236
+ return '';
237
+ }
238
+ else {
239
+ return `gt-sort-${sortOrder[sortIndex].order}`;
240
+ }
241
+ }
242
+ else {
243
+ return (sortOrder && sortOrder?.length === 1) || sortIndex < 0
244
+ ? null
245
+ : sortIndex + 1 + '';
246
+ }
247
+ }
248
+ }
249
+ SortClassPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: SortClassPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
250
+ SortClassPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.1.1", ngImport: i0, type: SortClassPipe, isStandalone: true, name: "sortClass" });
251
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: SortClassPipe, decorators: [{
252
+ type: Pipe,
253
+ args: [{
254
+ name: 'sortClass',
255
+ standalone: true,
256
+ }]
257
+ }] });
258
+
259
+ class DashCasePipe {
260
+ transform(s) {
261
+ return dashed(s);
262
+ }
263
+ }
264
+ DashCasePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: DashCasePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
265
+ DashCasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.1.1", ngImport: i0, type: DashCasePipe, isStandalone: true, name: "dashCase" });
266
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: DashCasePipe, decorators: [{
267
+ type: Pipe,
268
+ args: [{
269
+ name: 'dashCase',
270
+ standalone: true,
271
+ }]
272
+ }] });
273
+
274
+ class DynamicPipe {
275
+ constructor(injector) {
276
+ this.injector = injector;
277
+ }
278
+ transform(value, requiredPipe, pipeArgs) {
279
+ const injector = Injector.create({
280
+ name: 'DynamicPipe',
281
+ parent: this.injector,
282
+ providers: [{ provide: requiredPipe }],
283
+ });
284
+ const pipe = injector.get(requiredPipe);
285
+ return pipe.transform(value, ...(pipeArgs || []));
286
+ }
287
+ }
288
+ DynamicPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: DynamicPipe, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Pipe });
289
+ DynamicPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.1.1", ngImport: i0, type: DynamicPipe, isStandalone: true, name: "dynamicPipe" });
290
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: DynamicPipe, decorators: [{
291
+ type: Pipe,
292
+ args: [{
293
+ name: 'dynamicPipe',
294
+ standalone: true,
295
+ }]
296
+ }], ctorParameters: function () { return [{ type: i0.Injector }]; } });
297
+
298
+ class HighlightPipe {
299
+ transform(text, searchTerm) {
300
+ if (!searchTerm) {
301
+ return text;
302
+ }
303
+ const haystackAlwaysString = text + '';
304
+ let highlightedText = haystackAlwaysString; // fallback
305
+ let searchPattern;
306
+ try {
307
+ searchPattern = new RegExp('(' +
308
+ // @ts-ignore
309
+ searchTerm
310
+ .toLowerCase()
311
+ .match(/".*?"|[^ ]+/g) // extract words
312
+ .map((needle) => needle.replace(/"(.*?)"/, '$1') // strip away '"'
313
+ )
314
+ .join('|') + // combine words
315
+ ')', 'ig');
316
+ }
317
+ catch (error) {
318
+ return highlightedText;
319
+ }
320
+ const containsTagPattern = /(<.*?>)(.*)(<\/.*?>)/gi;
321
+ const containsTagMatches = containsTagPattern.exec(haystackAlwaysString);
322
+ if (containsTagMatches) {
323
+ // tag exists in haystack
324
+ highlightedText =
325
+ containsTagMatches[1] +
326
+ containsTagMatches[2].replace(searchPattern, '<span class="gt-highlight-search">$1</span>') +
327
+ containsTagMatches[3];
328
+ }
329
+ else {
330
+ highlightedText = haystackAlwaysString.replace(searchPattern, '<span class="gt-highlight-search">$1</span>');
331
+ }
332
+ return highlightedText;
333
+ }
334
+ }
335
+ HighlightPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: HighlightPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
336
+ HighlightPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.1.1", ngImport: i0, type: HighlightPipe, isStandalone: true, name: "highlight" });
337
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: HighlightPipe, decorators: [{
338
+ type: Pipe,
339
+ args: [{
340
+ name: 'highlight',
341
+ standalone: true,
342
+ }]
343
+ }] });
344
+
345
+ class RowSelectionPipe {
346
+ transform(row, selection, comparator, className) {
347
+ return className && comparator(row, selection) ? className : '';
348
+ }
349
+ }
350
+ RowSelectionPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: RowSelectionPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
351
+ RowSelectionPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.1.1", ngImport: i0, type: RowSelectionPipe, isStandalone: true, name: "rowSelection" });
352
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: RowSelectionPipe, decorators: [{
353
+ type: Pipe,
354
+ args: [{
355
+ name: 'rowSelection',
356
+ standalone: true,
357
+ }]
358
+ }] });
359
+
360
+ class CoreComponent {
361
+ constructor() {
362
+ this.unsubscribe$ = new Subject();
363
+ this._navigationKeys = [
364
+ 'ArrowDown',
365
+ 'ArrowUp',
366
+ 'ArrowLeft',
367
+ 'ArrowRight',
368
+ 'Home',
369
+ 'End',
370
+ ];
371
+ this._selectKeys = ['Enter', ' '];
372
+ this._customClasses = {
373
+ selectedRow: 'gt-selected',
374
+ activeRow: 'gt-active',
375
+ };
376
+ /** selection
377
+ * @description An object that contains the currently selected row(s) in the table. It's passed to the selection function to determine which rows should be selected.
378
+ * @type {any}
379
+ */
380
+ this.selection = {};
381
+ /** generateRowId
382
+ * @description Whether or not to generate a unique id for each row in the table. Defaults to `true`.
383
+ * @type {boolean}
384
+ */
385
+ this.generateRowId = true;
386
+ this.rowClick = new EventEmitter();
387
+ this.rowSelect = new EventEmitter();
388
+ this.sortOrderChange = new EventEmitter();
389
+ this._rowActive$ = new ReplaySubject(1);
390
+ this.rowActive = new EventEmitter();
391
+ this.columnSort = new EventEmitter();
392
+ /** page change event - emitted when current page/index changes for pagination */
393
+ this.pageChange = new EventEmitter();
394
+ this.rowActive$ = this._rowActive$.asObservable().pipe(distinctUntilChanged((p, q) => {
395
+ if (this.rowIdKey && p.row && q.row) {
396
+ return p.row[this.rowIdKey] === q.row[this.rowIdKey];
397
+ }
398
+ else if (this.generateRowId && p.row && q.row) {
399
+ return p.row._id === q.row._id;
400
+ }
401
+ else {
402
+ return p.index === q.index;
403
+ }
404
+ }), tap((event) => (this.activeRowIndex = event.index)), tap((event) => this.rowActive.emit(event)), shareReplay(1));
405
+ this.activeRowIndex = null;
406
+ this._loading$ = new ReplaySubject(1);
407
+ this._sortOrder$ = new BehaviorSubject([]);
408
+ this._searchBy$ = new ReplaySubject(1);
409
+ this.searchBy$ = this._searchBy$.pipe(startWith(''), map((value) => (isObservable(value) ? value : of(value))), switchMap((obs) => obs), shareReplay(1));
410
+ this._pagingInfo$ = new BehaviorSubject({
411
+ pageCurrent: null,
412
+ pageNext: null,
413
+ pagePrevious: null,
414
+ pageSize: null,
415
+ numberOfRecords: null,
416
+ //recordsAfterFilter: null,
417
+ //recordsAfterSearch: null,
418
+ //recordsAll: null,
419
+ });
420
+ // tslint:disable-next-line:variable-name
421
+ this._tableConfig$ = new BehaviorSubject({});
422
+ this.tableConfig$ = this._tableConfig$.pipe(map((value) => (isObservable(value) ? value : of(value))), switchMap((obs) => obs), tap((config) => (this._tableConfig = config)), shareReplay(1));
423
+ this._data$ = new ReplaySubject(1);
424
+ this.data$ = this._data$.pipe(map((value) => (isObservable(value) ? value : of(value))), switchMap((obs) => combineLatest([obs])), withLatestFrom(this.tableConfig$), map(([[data], config]) => {
425
+ // if columns or rows contains config for mapTo...
426
+ if ((config.columns &&
427
+ !!Object.values(config.columns).find((column) => !!column.mapTo)) ||
428
+ (config.rows &&
429
+ !!Object.values(config.rows).find((column) => !!column.mapTo))) {
430
+ // ...map data to new keys on row...
431
+ const newData = [];
432
+ for (let i = 0; i < data.length; i++) {
433
+ const row = data[i];
434
+ const newKeys = Object.entries(config.columns || config.rows || [])
435
+ .filter(([key, value]) => !!value.mapTo) // add keys for columns with mapTo config...
436
+ .reduce((previousValue, [key, value]) => ({
437
+ ...previousValue,
438
+ [key]: this.nestedValue(row, value.mapTo.path, value.mapTo?.missingValue),
439
+ }), {});
440
+ newData[i] = { ...row, ...newKeys };
441
+ }
442
+ data = newData;
443
+ }
444
+ if (this.generateRowId && !this.rowIdKey && data.length > 0) {
445
+ const dataWithId = [];
446
+ for (let i = 0; i < data.length; i++) {
447
+ dataWithId[i] = { ...data[i], _id: i };
448
+ }
449
+ data = dataWithId;
450
+ }
451
+ return { data, config };
452
+ }), switchMap((obs) => combineLatest([of(obs), this.sortOrder$, this.searchBy$])), map(([table, sortBy, searchBy]) => {
453
+ // create a new array reference and sort new array (prevent mutating existing state)
454
+ table.data = [...table.data];
455
+ return !sortBy?.length || table.config?.disableTableSort
456
+ ? searchBy && !this.tableInfo?.lazyLoaded
457
+ ? search(searchBy, false, table.data, table.config)
458
+ : table.data
459
+ : searchBy && !this.tableInfo?.lazyLoaded
460
+ ? search(searchBy, false, table.data, table.config)?.sort(sortOnMultipleKeys(sortBy))
461
+ : table.data?.sort(sortOnMultipleKeys(sortBy));
462
+ }), shareReplay(1));
463
+ this.calculations$ = combineLatest([this.data$, this.tableConfig$]).pipe(map(([data, config]) => calculate(data, config)), shareReplay(1));
464
+ this.table$ = combineLatest([
465
+ this.data$,
466
+ this.tableConfig$,
467
+ this._pagingInfo$,
468
+ ]).pipe(map(([sorted, config, pagingInfo]) => {
469
+ if (pagingInfo.pageCurrent !== null &&
470
+ pagingInfo.numberOfRecords !== null &&
471
+ pagingInfo.pageSize !== null) {
472
+ return {
473
+ data: [sorted],
474
+ config,
475
+ info: {
476
+ lazyLoaded: true,
477
+ numberOfRecords: pagingInfo.numberOfRecords,
478
+ pageSize: pagingInfo.pageSize,
479
+ pageTotal: pagingInfo.pageTotal ??
480
+ Math.ceil(pagingInfo.numberOfRecords / pagingInfo.pageSize),
481
+ },
482
+ };
483
+ }
484
+ // if pagination is disabled...
485
+ if (!config.pagination || config.pagination.length === 0) {
486
+ // ...return unaltered array
487
+ return {
488
+ data: [sorted],
489
+ config,
490
+ info: { numberOfRecords: sorted.length, pageTotal: 1 },
491
+ };
492
+ }
493
+ // return record set
494
+ return {
495
+ data: chunk(sorted, +(config.pagination.length || 0)),
496
+ config,
497
+ info: {
498
+ numberOfRecords: sorted.length,
499
+ pageSize: +(config.pagination.length || 0),
500
+ pageTotal: Math.ceil(sorted.length / +(config.pagination.length || 0)),
501
+ },
502
+ };
503
+ }), tap((meta) => this._tableInfo$.next(meta.info)), shareReplay(1));
504
+ this._tableInfo$ = new BehaviorSubject(undefined);
505
+ this._currentPaginationIndex$ = new BehaviorSubject(0);
506
+ this.currentPaginationIndex$ = combineLatest([
507
+ this._currentPaginationIndex$,
508
+ this.table$,
509
+ ]).pipe(map(([page, table]) => {
510
+ // determine last page
511
+ const lastPage = Math.ceil(table.info.numberOfRecords /
512
+ (table.info.pageSize ??
513
+ (table.config?.pagination?.length || table.info.numberOfRecords))) - 1;
514
+ // determine min/max position
515
+ return +page < 0 ? 0 : +page > lastPage ? lastPage : +page;
516
+ }), distinctUntilChanged(), tap((index) => this.pageChange.emit({ index })), shareReplay(1));
517
+ this.colspan$ = this.tableConfig$.pipe(switchMap((config) => config.columns
518
+ ? of(Object.values(config.columns || config.rows || {}).filter((value) => value.hidden !== true).length)
519
+ : this.data$.pipe(map((data) => data.length + 1))), shareReplay(1));
520
+ this.footerColspan$ = this.tableConfig$.pipe(map((config) => {
521
+ let colspan = 0;
522
+ Object.values(config?.footer?.columns || {}).forEach((calculations) => {
523
+ if (Object.values(calculations).filter((value) => value !== false)
524
+ .length >= 0) {
525
+ colspan += 1;
526
+ }
527
+ }, {});
528
+ return colspan;
529
+ }), shareReplay(1));
530
+ this.columnOrder = (a, b) => {
531
+ return (a.value.order || 0) - (b.value.order || 0);
532
+ };
533
+ this._unsubscribeFromKeyboardEvents$ = new Subject();
534
+ this._keyboardArrowEvent$ = fromEvent(document, 'keydown').pipe(filter((event) => [...this._navigationKeys, ...this._selectKeys].indexOf(event.key) > -1));
535
+ }
536
+ get navigationKeys() {
537
+ return this._navigationKeys;
538
+ }
539
+ /** navigationKeys
540
+ * @description An array of keyboard keys that will trigger navigation and active row, currently only supports arrow keys, home and end (omit key name from array to disable it)
541
+ * @type {string[]}
542
+ * @default ['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight', 'Home', 'End']
543
+ */
544
+ set navigationKeys(value) {
545
+ this._navigationKeys = value;
546
+ }
547
+ get selectKeys() {
548
+ return this._selectKeys;
549
+ }
550
+ /** selectKeys
551
+ * @description An array of keyboard keys that will trigger row selection (omit key name from array to disable it)
552
+ * @type {string[]}
553
+ * @default ['Enter', ' ']
554
+ */
555
+ set selectKeys(value) {
556
+ this._selectKeys = value;
557
+ }
558
+ get sortOrder$() {
559
+ return this._sortOrder$.asObservable();
560
+ }
561
+ set loading(isLoading) {
562
+ this._loading$.next(isLoading);
563
+ }
564
+ set paginationIndex(pageIndex) {
565
+ this._currentPaginationIndex$.next(pageIndex);
566
+ }
567
+ get paginationIndex() {
568
+ return this._currentPaginationIndex$.getValue();
569
+ }
570
+ set pagingInfo(value) {
571
+ if (value) {
572
+ this._pagingInfo$.next(value);
573
+ if (value.pageCurrent !== this._currentPaginationIndex$.getValue() + 1 &&
574
+ value.pageCurrent !== null) {
575
+ this.paginationIndex = value.pageCurrent - 1;
576
+ }
577
+ }
578
+ }
579
+ /** customClasses
580
+ * @description An object that contains custom classes for various elements in the table.
581
+ * @type {object} - { selectedRow: string, activeRow: string } - default classes are 'gt-selected' and 'gt-active'
582
+ */
583
+ set customClasses(classes) {
584
+ this._customClasses = { ...this._customClasses, ...classes };
585
+ }
586
+ get customClasses() {
587
+ return this._customClasses;
588
+ }
589
+ /** isRowSelectedFn
590
+ * @description Function to determine if row is selected or not.
591
+ * @type {fn} A function that receives a row object and optional state for current selection that can be used to determine if row should be marked as selected or not. */
592
+ set isRowSelectedFn(fn) {
593
+ this._isRowSelectedFn = fn;
594
+ }
595
+ get isRowSelectedFn() {
596
+ return this._isRowSelectedFn;
597
+ }
598
+ /** trackRowByFn
599
+ * @description A function that returns a unique identifier for each row in the table to optimize rendering when data is added or removed.
600
+ * @type fn - TrackByFunction to retrieve unique id based on index and/or row. Defaults to using `row[this.rowIdKey]`.
601
+ */
602
+ set trackRowByFn(fn) {
603
+ this._trackRowByFn = fn;
604
+ }
605
+ get trackRowByFn() {
606
+ return this._trackRowByFn;
607
+ }
608
+ _trackRowByFn(index, row) {
609
+ return this.rowIdKey ? row[this.rowIdKey] : row?._id;
610
+ }
611
+ set search(string) {
612
+ this._searchBy$.next(string);
613
+ }
614
+ set config(config) {
615
+ this._tableConfig$.next(config);
616
+ }
617
+ set data(data) {
618
+ if (data) {
619
+ this._data$.next(data);
620
+ }
621
+ }
622
+ set sortOrder(sortConfig) {
623
+ if (JSON.stringify(sortConfig) !== JSON.stringify(this._sortOrder$.value)) {
624
+ this.sortOrderChange.emit(sortConfig);
625
+ this._sortOrder$.next(sortConfig);
626
+ }
627
+ }
628
+ _rowClick(row, index, event) {
629
+ this.rowClick.emit({ row, index, event });
630
+ }
631
+ _rowActive(row, index, event) {
632
+ this.rowSelect.emit({ row, index, event });
633
+ }
634
+ activateRow(arg, event) {
635
+ if (typeof arg === 'number') {
636
+ this.table$
637
+ .pipe(pluck('data'), map((data) => data[this.paginationIndex][arg]), take(1), takeUntil(this.unsubscribe$))
638
+ .subscribe((row) => this._activateRow(row, arg, event));
639
+ }
640
+ else if (typeof arg === 'string') {
641
+ // TODO: implement hover by id
642
+ }
643
+ else {
644
+ this._activateRow(null, null);
645
+ }
646
+ }
647
+ _activateRow(row, index, event) {
648
+ this._rowActive$.next({ row, index, event });
649
+ }
650
+ get loading$() {
651
+ return this._loading$.pipe(startWith(false), map((value) => (isObservable(value) ? value : of(value))), switchMap((obs) => obs), shareReplay(1));
652
+ }
653
+ /** tableInfo$ - returns observable for table info
654
+ * @return Observable<TableInfo> */
655
+ get tableInfo$() {
656
+ return this._tableInfo$.asObservable().pipe(filter((info) => !!info), shareReplay(1));
657
+ }
658
+ /** tableInfo - returns the current table info
659
+ * @return TableInfo */
660
+ get tableInfo() {
661
+ return this._tableInfo$.getValue();
662
+ }
663
+ /** sortByKey - Sort by key in table row
664
+ * @param key - key to sort by
665
+ * @param { MouseEvent } [$event] - Mouse event triggering sort, if shift key is pressed sort key will be added to already present sort keys
666
+ */
667
+ sortByKey(key, $event) {
668
+ const shiftKey = $event?.shiftKey === true;
669
+ const currentOrder = this._sortOrder$.value;
670
+ let sortOrder = 'asc';
671
+ let newOrder = [];
672
+ // if shift key is pressed while sorting...
673
+ if (shiftKey) {
674
+ // ...check if key is already sorted
675
+ const existingSortPosition = currentOrder.findIndex((value) => value.key === key);
676
+ if (existingSortPosition === -1) {
677
+ // ...if key is not sorted, add it to the end of the sort order
678
+ newOrder = [...currentOrder, { key, order: 'asc' }];
679
+ }
680
+ else {
681
+ // ...if key is already sorted, toggle sort order
682
+ sortOrder = currentOrder[existingSortPosition].order;
683
+ const newSortOrder = sortOrder === 'asc' ? 'desc' : 'asc';
684
+ newOrder = [...currentOrder];
685
+ newOrder[existingSortPosition] = {
686
+ ...newOrder[existingSortPosition],
687
+ order: newSortOrder,
688
+ };
689
+ }
690
+ }
691
+ else {
692
+ // ...else if shift key is not pressed...
693
+ if (currentOrder.length > 0) {
694
+ // ...check if key is already sorted
695
+ const existingSortPosition = currentOrder.findIndex((value) => value.key === key);
696
+ // ...if key is already sorted, toggle sort order
697
+ if (existingSortPosition === -1) {
698
+ newOrder = [{ key, order: 'asc' }];
699
+ }
700
+ else {
701
+ sortOrder = currentOrder[existingSortPosition].order;
702
+ const newSortOrder = sortOrder === 'asc' ? 'desc' : 'asc';
703
+ newOrder = [{ key, order: newSortOrder }];
704
+ }
705
+ }
706
+ else {
707
+ // ...if key is not sorted set sort order for key to ascending
708
+ newOrder = [{ key, order: sortOrder }];
709
+ }
710
+ }
711
+ // create sort event
712
+ const sortEvent = {
713
+ key,
714
+ order: sortOrder,
715
+ currentSortOrder: newOrder,
716
+ addSortKey: shiftKey,
717
+ };
718
+ // if event is passed to sort function...
719
+ if ($event) {
720
+ // ...emit it as well
721
+ sortEvent.event = $event;
722
+ }
723
+ // emit sort event
724
+ this.columnSort.emit(sortEvent);
725
+ // if table is not lazy loaded (sorting is then handled server-side)...
726
+ if (!this.tableInfo?.lazyLoaded) {
727
+ // ...update sort order
728
+ this.sortOrder = newOrder;
729
+ }
730
+ }
731
+ nestedValue(object, mapTo, missingValue = null) {
732
+ const levels = mapTo.split('.');
733
+ return levels.reduce((previousValue, currentValue, index) => previousValue[currentValue] ||
734
+ (index === levels.length - 1 ? missingValue : {}), object);
735
+ }
736
+ listenToKeyboardEvents() {
737
+ if (!this._tableConfig?.activateRowOnKeyboardNavigation) {
738
+ return;
739
+ }
740
+ this._unsubscribeFromKeyboardEvents$.next(true);
741
+ this._keyboardArrowEvent$
742
+ .pipe(withLatestFrom(this.data$, this.currentPaginationIndex$, this.tableInfo$), takeUntil(this._unsubscribeFromKeyboardEvents$), takeUntil(this.unsubscribe$))
743
+ .subscribe(([event, rows, currentPage, tableInfo]) => {
744
+ const selectEvent = this._selectKeys.includes(event.key);
745
+ if (selectEvent && this.activeRowIndex !== null) {
746
+ const rowIndex = this.activeRowIndex + currentPage * (tableInfo?.pageSize ?? 0);
747
+ this._rowActive(rows[rowIndex], rowIndex, event);
748
+ return;
749
+ }
750
+ const navigationEvent = this._navigationKeys.includes(event.key);
751
+ if (navigationEvent) {
752
+ this._handleNavigationEvent(event, rows, currentPage, tableInfo);
753
+ }
754
+ });
755
+ }
756
+ unsubscribeFromKeyboardEvents(tableRef) {
757
+ if (!this._tableConfig?.activateRowOnKeyboardNavigation) {
758
+ return;
759
+ }
760
+ // only unsubscribe if table is not focused
761
+ if (tableRef !== document.activeElement) {
762
+ if (this._tableConfig?.activateRowOnHover) {
763
+ // unset active row
764
+ this.activateRow(null);
765
+ }
766
+ this._unsubscribeFromKeyboardEvents$.next(true);
767
+ }
768
+ }
769
+ _handleNavigationEvent(event, rows, currentPage, tableInfo) {
770
+ const hasPagination = (tableInfo?.pageTotal || 0) > 1 && tableInfo;
771
+ const lastRowIndex = rows.length - 1;
772
+ let newIndex = this.activeRowIndex;
773
+ let indexModifier = 0;
774
+ if (event.key === 'Home') {
775
+ this.paginationIndex = 0;
776
+ this.activateRow(0, event);
777
+ return;
778
+ }
779
+ if (event.key === 'End') {
780
+ const indexOfLastRecord = hasPagination
781
+ ? rows.length - (tableInfo.pageTotal - 1) * tableInfo.pageSize - 1
782
+ : lastRowIndex;
783
+ if (tableInfo?.pageTotal) {
784
+ this.paginationIndex = tableInfo.pageTotal - 1;
785
+ }
786
+ this.activateRow(indexOfLastRecord, event);
787
+ return;
788
+ }
789
+ if (event.key === 'ArrowDown') {
790
+ indexModifier = 1;
791
+ }
792
+ else if (event.key === 'ArrowUp') {
793
+ indexModifier = -1;
794
+ }
795
+ if (newIndex === null) {
796
+ newIndex = 0;
797
+ }
798
+ else if (newIndex + indexModifier >= 0 &&
799
+ newIndex + indexModifier <= lastRowIndex) {
800
+ newIndex = newIndex + indexModifier;
801
+ }
802
+ if (hasPagination && tableInfo?.pageSize) {
803
+ const isNotLastPage = currentPage + 1 < tableInfo.pageTotal;
804
+ const recordsOnLastPage = rows.length - (tableInfo.pageTotal - 1) * tableInfo.pageSize - 1;
805
+ const maxIndex = isNotLastPage
806
+ ? tableInfo?.pageSize - 1
807
+ : recordsOnLastPage;
808
+ if (event.key === 'ArrowLeft' && currentPage > 0) {
809
+ this.paginationIndex = currentPage - 1;
810
+ this.activateRow(newIndex, event);
811
+ return;
812
+ }
813
+ else if (event.key === 'ArrowRight' && isNotLastPage) {
814
+ if (currentPage + 1 === tableInfo.pageTotal - 1 &&
815
+ newIndex > recordsOnLastPage) {
816
+ this.activateRow(recordsOnLastPage, event);
817
+ }
818
+ this.paginationIndex = currentPage + 1;
819
+ this.activateRow(newIndex, event);
820
+ return;
821
+ }
822
+ if (currentPage > 0 &&
823
+ indexModifier < 0 &&
824
+ newIndex + indexModifier <= lastRowIndex &&
825
+ (this.activeRowIndex || 0) + indexModifier < 0) {
826
+ // set last row of previous page as active
827
+ this.activateRow(tableInfo?.pageSize - 1, event);
828
+ this.paginationIndex = currentPage - 1;
829
+ return;
830
+ }
831
+ const pageIndex = newIndex % tableInfo?.pageSize;
832
+ if (newIndex > maxIndex && currentPage + 1 < tableInfo.pageTotal) {
833
+ this.paginationIndex = currentPage + 1;
834
+ }
835
+ this.activateRow(pageIndex > maxIndex ? maxIndex : pageIndex, event);
836
+ return;
837
+ }
838
+ this.activateRow(newIndex, event);
839
+ }
840
+ ngOnDestroy() {
841
+ this.unsubscribe$.next(true);
842
+ this.unsubscribe$.complete();
843
+ }
844
+ }
845
+ CoreComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: CoreComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
846
+ CoreComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.1", type: CoreComponent, isStandalone: true, selector: "angular-generic-table", inputs: { navigationKeys: "navigationKeys", selectKeys: "selectKeys", loading: "loading", paginationIndex: "paginationIndex", pagingInfo: "pagingInfo", customClasses: "customClasses", isRowSelectedFn: "isRowSelectedFn", selection: "selection", rowIdKey: "rowIdKey", generateRowId: "generateRowId", trackRowByFn: "trackRowByFn", search: "search", config: "config", data: "data", sortOrder: "sortOrder" }, outputs: { rowClick: "rowClick", rowSelect: "rowSelect", sortOrderChange: "sortOrderChange", rowActive: "rowActive", columnSort: "columnSort", pageChange: "pageChange" }, ngImport: i0, template: "<table\n [ngClass]=\"(tableConfig$ | async)?.class || 'table'\"\n [class.table-mobile]=\"(tableConfig$ | async)?.mobileLayout\"\n [class.table-horizontal]=\"(tableConfig$ | async)?.rows\"\n [class.table-loading]=\"loading$ | async\"\n [class.gt-sticky-row-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.row && (tableConfig$ | async)?.rows\n \"\n [class.gt-sticky-column-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.column\n \"\n [attr.aria-busy]=\"(loading$ | async) === true ? true : null\"\n [tabindex]=\"(tableConfig$ | async)?.activateRowOnKeyboardNavigation ? 0 : -1\"\n #tableRef\n (focus)=\"listenToKeyboardEvents()\"\n (focusout)=\"unsubscribeFromKeyboardEvents(tableRef)\"\n (mouseenter)=\"listenToKeyboardEvents()\"\n (mouseleave)=\"unsubscribeFromKeyboardEvents(tableRef)\"\n>\n <thead>\n <tr\n *ngIf=\"{\n config: (tableConfig$ | async)!,\n isLoading: loading$ | async\n } as table\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <th\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [class.disabled]=\"table.isLoading\"\n [attr.aria-sort]=\"sortOrder$ | async | sortClass: column.key:'aria'\"\n [class.gt-sortable]=\"true\"\n scope=\"col\"\n >\n <button\n *ngIf=\"column.value?.sortable\"\n [attr.data-sort-order]=\"\n sortOrder$ | async | sortClass: column.key:'order'\n \"\n class=\"gt-sort\"\n (click)=\"\n table.isLoading ||\n !column.value.sortable ||\n sortByKey(column.key, $event)\n \"\n >\n <span *ngIf=\"column.value?.header !== false\">{{\n column.value.header || column.key | capitalCase\n }}</span>\n </button>\n <span\n *ngIf=\"!column.value?.sortable && column.value?.header !== false\"\n >{{ column.value.header || column.key | capitalCase }}</span\n >\n </th>\n </ng-container>\n <ng-container\n *ngIf=\"\n ((table?.config?.rows | keyvalue: columnOrder) || [])[0] as headerRow\n \"\n >\n <th\n class=\"row-header\"\n [attr.aria-sort]=\"\n sortOrder$ | async | sortClass: headerRow.key:'aria'\n \"\n ngClass=\"{{ headerRow.value.sortable ? 'sort ' : '' }} {{\n sortOrder$ | async | sortClass: headerRow.key\n }} {{ (headerRow.key | dashCase) + '-column' }}\"\n (click)=\"\n table.isLoading ||\n !headerRow.value.sortable ||\n sortByKey(headerRow.key, $event)\n \"\n scope=\"col\"\n >\n <ng-container *ngIf=\"headerRow?.value?.header !== false\">{{\n headerRow?.value?.header || headerRow.key | capitalCase\n }}</ng-container>\n </th>\n <th\n *ngFor=\"let column of ((table$ | async)?.data || [])[0]\"\n ngClass=\"{{ headerRow.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[headerRow.key].templateRef\n ? templateRef\n : (table.config.rows || {})[headerRow.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: headerRow,\n transform: (table.config.rows || {})[headerRow.key].transform,\n templateRef: (table.config.rows || {})[headerRow.key].templateRef,\n index: 0\n }\"\n >\n </ng-container>\n </th>\n </ng-container>\n </tr>\n </thead>\n <tbody *ngIf=\"loading$ | async; else tableContent\">\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-loading\"></ng-content>\n </td>\n </tr>\n </tbody>\n <tfoot *ngIf=\"(table$ | async)! as table\">\n <ng-container *ngIf=\"table.data.length > 0 && !(loading$ | async)\">\n <ng-container *ngIf=\"(calculations$ | async)! as calculations\">\n <tr\n *ngFor=\"let calculation of calculations.calculations; let i = index\"\n >\n <ng-container\n *ngIf=\"{\n showHeader: (colspan$ | async) !== (footerColspan$ | async)\n } as footerRow\"\n >\n <th\n *ngIf=\"footerRow.showHeader\"\n [colSpan]=\"\n ((colspan$ | async) || 0) - ((footerColspan$ | async) || 0)\n \"\n scope=\"row\"\n >\n <ng-container\n *ngIf=\"table.config?.footer?.headers?.[calculation] as showHeader\"\n >{{showHeader === true ? (calculation | capitalCase): table.config.footer?.headers?.[calculation]}}\n </ng-container>\n </th>\n <ng-container\n *ngFor=\"\n let column of table.config?.columns | keyvalue: columnOrder\n \"\n >\n <td\n *ngIf=\"\n !column.value?.hidden && calculations.calculated[column.key]\n \"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-header]=\"\n !footerRow.showHeader && table.config.footer?.headers?.[calculation]\n ? table.config.footer?.headers?.[calculation] === true ? (calculation | capitalCase) : table.config.footer?.headers?.[calculation]\n : null\n \"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n [class.gt-no-content]=\"\n !calculations.calculated[column.key][calculation]\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformFooter\n : rawFooter\n \"\n [ngTemplateOutletContext]=\"{\n value: calculations.calculated[column.key][calculation],\n row: calculations.calculated[column.key],\n column: calculation,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n transform: (table.config.columns || {})[column.key]\n .transform\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </ng-container>\n </tr>\n </ng-container>\n </ng-container>\n </tfoot>\n</table>\n<ng-template #tableContent>\n <ng-container *ngIf=\"(table$ | async)! as table\">\n <tbody *ngIf=\"(table!.data![0] || table!.data!).length > 0; else noData\">\n <ng-container *ngIf=\"table.config.columns\">\n <tr\n *ngFor=\"\n let row of table!.data![\n table.info.lazyLoaded ? 0 : (currentPaginationIndex$ | async) || 0\n ];\n trackBy: trackRowByFn;\n let i = index\n \"\n [attr.id]=\"'tableRow_' + i\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseenter)=\"\n table?.config?.activateRowOnHover && _activateRow(row, i, $event)\n \"\n (mouseleave)=\"\n table?.config?.activateRowOnHover &&\n _activateRow(null, null, $event)\n \"\n [ngClass]=\"[\n !!isRowSelectedFn\n ? (row\n | rowSelection\n : selection\n : isRowSelectedFn\n : customClasses.selectedRow)\n : '',\n (rowActive$ | async)?.index === i ? customClasses.activeRow : ''\n ]\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <td\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (searchBy$ | async) &&\n !(table.config.columns || {})[column.key].templateRef\n ? highlighted\n : (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: row,\n column: column,\n search: (searchBy$ | async),\n transform: (table.config.columns || {})[column.key].transform,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n index: i,\n data: table.data[\n table.info.lazyLoaded\n ? 0\n : (currentPaginationIndex$ | async) || 0\n ]\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </tr>\n </ng-container>\n <ng-container *ngIf=\"table.config.rows\">\n <ng-container\n *ngFor=\"\n let row of table?.config?.rows | keyvalue: columnOrder | slice: 1;\n let i = index\n \"\n >\n <tr\n *ngIf=\"!row.value?.hidden\"\n [attr.id]=\"'tableRow_' + i\"\n ngClass=\"{{ (row.key | dashCase) + '-row' }}\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseenter)=\"\n table?.config?.activateRowOnHover && _activateRow(row, i, $event)\n \"\n (mouseleave)=\"\n table?.config?.activateRowOnHover &&\n _activateRow(null, null, $event)\n \"\n [ngClass]=\"[\n !!isRowSelectedFn\n ? (row\n | rowSelection\n : selection\n : isRowSelectedFn\n : customClasses.selectedRow)\n : '',\n (rowActive$ | async)?.index === i ? customClasses.activeRow : ''\n ]\"\n >\n <th class=\"row-header\" scope=\"row\">\n {{ row.value.header || row.key | capitalCase }}\n </th>\n <td\n *ngFor=\"let column of (table?.data || [])[0]; let y = index\"\n ngClass=\"{{ row.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[row.key].templateRef\n ? templateRef\n : (table.config.rows || {})[row.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: row,\n transform: (table.config.rows || {})[row.key].transform,\n templateRef: (table.config.rows || {})[row.key].templateRef,\n index: table.config.rows ? y : i,\n data: table.data[\n table.info.lazyLoaded\n ? 0\n : (currentPaginationIndex$ | async) || 0\n ]\n }\"\n >\n </ng-container>\n </td>\n </tr>\n </ng-container>\n </ng-container>\n </tbody>\n </ng-container>\n</ng-template>\n<ng-template #noData>\n <tbody>\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-no-data\"></ng-content>\n </td>\n </tr>\n </tbody>\n</ng-template>\n<ng-template\n #highlighted\n let-row=\"row\"\n let-column=\"column\"\n let-search=\"search\"\n let-transform=\"transform\"\n>\n <div\n *ngIf=\"!transform\"\n [innerHTML]=\"row[column.key] | highlight: search\"\n ></div>\n <div\n *ngIf=\"transform\"\n [innerHTML]=\"\n row[column.key]\n | dynamicPipe: transform.pipe:transform?.args\n | highlight: search\n \"\n ></div>\n</ng-template>\n<ng-template #rawData let-row=\"row\" let-column=\"column\">\n {{ row[column.key] }}\n</ng-template>\n<ng-template\n #transformData\n let-row=\"row\"\n let-column=\"column\"\n let-transform=\"transform\"\n let-data=\"data\"\n>\n {{ row[column.key] | dynamicPipe: transform.pipe:transform?.args }}\n</ng-template>\n<ng-template #transformFooter let-value=\"value\" let-transform=\"transform\">\n {{\n (value | dynamicPipe: transform.pipe:transform?.args) ||\n (tableConfig$ | async)?.footer?.emptyContent\n }}\n</ng-template>\n<ng-template #rawFooter let-value=\"value\">\n {{ value || (tableConfig$ | async)?.footer?.emptyContent }}\n</ng-template>\n<ng-template\n #templateRef\n let-row=\"row\"\n let-column=\"column\"\n let-index=\"index\"\n let-templateRef=\"templateRef\"\n let-data=\"data\"\n>\n <ng-container\n [ngTemplateOutlet]=\"templateRef\"\n [ngTemplateOutletContext]=\"{\n row: row,\n col: column,\n index: index,\n data: data\n }\"\n ></ng-container>\n</ng-template>\n", dependencies: [{ kind: "pipe", type: CapitalCasePipe, name: "capitalCase" }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }, { kind: "pipe", type: SortClassPipe, name: "sortClass" }, { kind: "pipe", type: DashCasePipe, name: "dashCase" }, { kind: "pipe", type: RowSelectionPipe, name: "rowSelection" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: SlicePipe, name: "slice" }, { kind: "pipe", type: DynamicPipe, name: "dynamicPipe" }, { kind: "pipe", type: HighlightPipe, name: "highlight" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
847
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: CoreComponent, decorators: [{
848
+ type: Component,
849
+ args: [{ selector: 'angular-generic-table', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
850
+ CapitalCasePipe,
851
+ KeyValuePipe,
852
+ SortClassPipe,
853
+ DashCasePipe,
854
+ RowSelectionPipe,
855
+ AsyncPipe,
856
+ NgTemplateOutlet,
857
+ SlicePipe,
858
+ DynamicPipe,
859
+ HighlightPipe,
860
+ NgClass,
861
+ NgIf,
862
+ NgForOf,
863
+ ], template: "<table\n [ngClass]=\"(tableConfig$ | async)?.class || 'table'\"\n [class.table-mobile]=\"(tableConfig$ | async)?.mobileLayout\"\n [class.table-horizontal]=\"(tableConfig$ | async)?.rows\"\n [class.table-loading]=\"loading$ | async\"\n [class.gt-sticky-row-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.row && (tableConfig$ | async)?.rows\n \"\n [class.gt-sticky-column-header]=\"\n (tableConfig$ | async)?.stickyHeaders?.column\n \"\n [attr.aria-busy]=\"(loading$ | async) === true ? true : null\"\n [tabindex]=\"(tableConfig$ | async)?.activateRowOnKeyboardNavigation ? 0 : -1\"\n #tableRef\n (focus)=\"listenToKeyboardEvents()\"\n (focusout)=\"unsubscribeFromKeyboardEvents(tableRef)\"\n (mouseenter)=\"listenToKeyboardEvents()\"\n (mouseleave)=\"unsubscribeFromKeyboardEvents(tableRef)\"\n>\n <thead>\n <tr\n *ngIf=\"{\n config: (tableConfig$ | async)!,\n isLoading: loading$ | async\n } as table\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <th\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [class.disabled]=\"table.isLoading\"\n [attr.aria-sort]=\"sortOrder$ | async | sortClass: column.key:'aria'\"\n [class.gt-sortable]=\"true\"\n scope=\"col\"\n >\n <button\n *ngIf=\"column.value?.sortable\"\n [attr.data-sort-order]=\"\n sortOrder$ | async | sortClass: column.key:'order'\n \"\n class=\"gt-sort\"\n (click)=\"\n table.isLoading ||\n !column.value.sortable ||\n sortByKey(column.key, $event)\n \"\n >\n <span *ngIf=\"column.value?.header !== false\">{{\n column.value.header || column.key | capitalCase\n }}</span>\n </button>\n <span\n *ngIf=\"!column.value?.sortable && column.value?.header !== false\"\n >{{ column.value.header || column.key | capitalCase }}</span\n >\n </th>\n </ng-container>\n <ng-container\n *ngIf=\"\n ((table?.config?.rows | keyvalue: columnOrder) || [])[0] as headerRow\n \"\n >\n <th\n class=\"row-header\"\n [attr.aria-sort]=\"\n sortOrder$ | async | sortClass: headerRow.key:'aria'\n \"\n ngClass=\"{{ headerRow.value.sortable ? 'sort ' : '' }} {{\n sortOrder$ | async | sortClass: headerRow.key\n }} {{ (headerRow.key | dashCase) + '-column' }}\"\n (click)=\"\n table.isLoading ||\n !headerRow.value.sortable ||\n sortByKey(headerRow.key, $event)\n \"\n scope=\"col\"\n >\n <ng-container *ngIf=\"headerRow?.value?.header !== false\">{{\n headerRow?.value?.header || headerRow.key | capitalCase\n }}</ng-container>\n </th>\n <th\n *ngFor=\"let column of ((table$ | async)?.data || [])[0]\"\n ngClass=\"{{ headerRow.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[headerRow.key].templateRef\n ? templateRef\n : (table.config.rows || {})[headerRow.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: headerRow,\n transform: (table.config.rows || {})[headerRow.key].transform,\n templateRef: (table.config.rows || {})[headerRow.key].templateRef,\n index: 0\n }\"\n >\n </ng-container>\n </th>\n </ng-container>\n </tr>\n </thead>\n <tbody *ngIf=\"loading$ | async; else tableContent\">\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-loading\"></ng-content>\n </td>\n </tr>\n </tbody>\n <tfoot *ngIf=\"(table$ | async)! as table\">\n <ng-container *ngIf=\"table.data.length > 0 && !(loading$ | async)\">\n <ng-container *ngIf=\"(calculations$ | async)! as calculations\">\n <tr\n *ngFor=\"let calculation of calculations.calculations; let i = index\"\n >\n <ng-container\n *ngIf=\"{\n showHeader: (colspan$ | async) !== (footerColspan$ | async)\n } as footerRow\"\n >\n <th\n *ngIf=\"footerRow.showHeader\"\n [colSpan]=\"\n ((colspan$ | async) || 0) - ((footerColspan$ | async) || 0)\n \"\n scope=\"row\"\n >\n <ng-container\n *ngIf=\"table.config?.footer?.headers?.[calculation] as showHeader\"\n >{{showHeader === true ? (calculation | capitalCase): table.config.footer?.headers?.[calculation]}}\n </ng-container>\n </th>\n <ng-container\n *ngFor=\"\n let column of table.config?.columns | keyvalue: columnOrder\n \"\n >\n <td\n *ngIf=\"\n !column.value?.hidden && calculations.calculated[column.key]\n \"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-header]=\"\n !footerRow.showHeader && table.config.footer?.headers?.[calculation]\n ? table.config.footer?.headers?.[calculation] === true ? (calculation | capitalCase) : table.config.footer?.headers?.[calculation]\n : null\n \"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n [class.gt-no-content]=\"\n !calculations.calculated[column.key][calculation]\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformFooter\n : rawFooter\n \"\n [ngTemplateOutletContext]=\"{\n value: calculations.calculated[column.key][calculation],\n row: calculations.calculated[column.key],\n column: calculation,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n transform: (table.config.columns || {})[column.key]\n .transform\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </ng-container>\n </tr>\n </ng-container>\n </ng-container>\n </tfoot>\n</table>\n<ng-template #tableContent>\n <ng-container *ngIf=\"(table$ | async)! as table\">\n <tbody *ngIf=\"(table!.data![0] || table!.data!).length > 0; else noData\">\n <ng-container *ngIf=\"table.config.columns\">\n <tr\n *ngFor=\"\n let row of table!.data![\n table.info.lazyLoaded ? 0 : (currentPaginationIndex$ | async) || 0\n ];\n trackBy: trackRowByFn;\n let i = index\n \"\n [attr.id]=\"'tableRow_' + i\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseenter)=\"\n table?.config?.activateRowOnHover && _activateRow(row, i, $event)\n \"\n (mouseleave)=\"\n table?.config?.activateRowOnHover &&\n _activateRow(null, null, $event)\n \"\n [ngClass]=\"[\n !!isRowSelectedFn\n ? (row\n | rowSelection\n : selection\n : isRowSelectedFn\n : customClasses.selectedRow)\n : '',\n (rowActive$ | async)?.index === i ? customClasses.activeRow : ''\n ]\"\n >\n <ng-container\n *ngFor=\"let column of table.config?.columns | keyvalue: columnOrder\"\n >\n <td\n *ngIf=\"!column.value?.hidden\"\n ngClass=\"{{ (column.key | dashCase) + '-column' }} {{\n column.value.class\n }}\"\n [attr.data-label]=\"\n table.config.mobileLayout && column.value.mobileHeader\n ? column.value.mobileHeader !== true\n ? column.value.mobileHeader\n : (column.value.header || column.key | capitalCase)\n : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (searchBy$ | async) &&\n !(table.config.columns || {})[column.key].templateRef\n ? highlighted\n : (table.config.columns || {})[column.key].templateRef\n ? templateRef\n : (table.config.columns || {})[column.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: row,\n column: column,\n search: (searchBy$ | async),\n transform: (table.config.columns || {})[column.key].transform,\n templateRef: (table.config.columns || {})[column.key]\n .templateRef,\n index: i,\n data: table.data[\n table.info.lazyLoaded\n ? 0\n : (currentPaginationIndex$ | async) || 0\n ]\n }\"\n ></ng-container>\n </td>\n </ng-container>\n </tr>\n </ng-container>\n <ng-container *ngIf=\"table.config.rows\">\n <ng-container\n *ngFor=\"\n let row of table?.config?.rows | keyvalue: columnOrder | slice: 1;\n let i = index\n \"\n >\n <tr\n *ngIf=\"!row.value?.hidden\"\n [attr.id]=\"'tableRow_' + i\"\n ngClass=\"{{ (row.key | dashCase) + '-row' }}\"\n (click)=\"table?.config?.rowClick && _rowClick(row, i, $event)\"\n (mouseenter)=\"\n table?.config?.activateRowOnHover && _activateRow(row, i, $event)\n \"\n (mouseleave)=\"\n table?.config?.activateRowOnHover &&\n _activateRow(null, null, $event)\n \"\n [ngClass]=\"[\n !!isRowSelectedFn\n ? (row\n | rowSelection\n : selection\n : isRowSelectedFn\n : customClasses.selectedRow)\n : '',\n (rowActive$ | async)?.index === i ? customClasses.activeRow : ''\n ]\"\n >\n <th class=\"row-header\" scope=\"row\">\n {{ row.value.header || row.key | capitalCase }}\n </th>\n <td\n *ngFor=\"let column of (table?.data || [])[0]; let y = index\"\n ngClass=\"{{ row.value.class }}\"\n >\n <ng-container\n [ngTemplateOutlet]=\"\n (table.config.rows || {})[row.key].templateRef\n ? templateRef\n : (table.config.rows || {})[row.key].transform\n ? transformData\n : rawData\n \"\n [ngTemplateOutletContext]=\"{\n row: column,\n column: row,\n transform: (table.config.rows || {})[row.key].transform,\n templateRef: (table.config.rows || {})[row.key].templateRef,\n index: table.config.rows ? y : i,\n data: table.data[\n table.info.lazyLoaded\n ? 0\n : (currentPaginationIndex$ | async) || 0\n ]\n }\"\n >\n </ng-container>\n </td>\n </tr>\n </ng-container>\n </ng-container>\n </tbody>\n </ng-container>\n</ng-template>\n<ng-template #noData>\n <tbody>\n <tr>\n <td class=\"p-0\" [colSpan]=\"colspan$ | async\">\n <ng-content select=\".table-no-data\"></ng-content>\n </td>\n </tr>\n </tbody>\n</ng-template>\n<ng-template\n #highlighted\n let-row=\"row\"\n let-column=\"column\"\n let-search=\"search\"\n let-transform=\"transform\"\n>\n <div\n *ngIf=\"!transform\"\n [innerHTML]=\"row[column.key] | highlight: search\"\n ></div>\n <div\n *ngIf=\"transform\"\n [innerHTML]=\"\n row[column.key]\n | dynamicPipe: transform.pipe:transform?.args\n | highlight: search\n \"\n ></div>\n</ng-template>\n<ng-template #rawData let-row=\"row\" let-column=\"column\">\n {{ row[column.key] }}\n</ng-template>\n<ng-template\n #transformData\n let-row=\"row\"\n let-column=\"column\"\n let-transform=\"transform\"\n let-data=\"data\"\n>\n {{ row[column.key] | dynamicPipe: transform.pipe:transform?.args }}\n</ng-template>\n<ng-template #transformFooter let-value=\"value\" let-transform=\"transform\">\n {{\n (value | dynamicPipe: transform.pipe:transform?.args) ||\n (tableConfig$ | async)?.footer?.emptyContent\n }}\n</ng-template>\n<ng-template #rawFooter let-value=\"value\">\n {{ value || (tableConfig$ | async)?.footer?.emptyContent }}\n</ng-template>\n<ng-template\n #templateRef\n let-row=\"row\"\n let-column=\"column\"\n let-index=\"index\"\n let-templateRef=\"templateRef\"\n let-data=\"data\"\n>\n <ng-container\n [ngTemplateOutlet]=\"templateRef\"\n [ngTemplateOutletContext]=\"{\n row: row,\n col: column,\n index: index,\n data: data\n }\"\n ></ng-container>\n</ng-template>\n" }]
864
+ }], propDecorators: { navigationKeys: [{
865
+ type: Input
866
+ }], selectKeys: [{
867
+ type: Input
868
+ }], loading: [{
869
+ type: Input
870
+ }], paginationIndex: [{
871
+ type: Input
872
+ }], pagingInfo: [{
873
+ type: Input
874
+ }], customClasses: [{
875
+ type: Input
876
+ }], isRowSelectedFn: [{
877
+ type: Input
878
+ }], selection: [{
879
+ type: Input
880
+ }], rowIdKey: [{
881
+ type: Input
882
+ }], generateRowId: [{
883
+ type: Input
884
+ }], trackRowByFn: [{
885
+ type: Input
886
+ }], search: [{
887
+ type: Input
888
+ }], config: [{
889
+ type: Input
890
+ }], data: [{
891
+ type: Input
892
+ }], sortOrder: [{
893
+ type: Input
894
+ }], rowClick: [{
895
+ type: Output
896
+ }], rowSelect: [{
897
+ type: Output
898
+ }], sortOrderChange: [{
899
+ type: Output
900
+ }], rowActive: [{
901
+ type: Output
902
+ }], columnSort: [{
903
+ type: Output
904
+ }], pageChange: [{
905
+ type: Output
906
+ }] } });
907
+
908
+ class GtDeltaComponent {
909
+ get value() {
910
+ return this._value;
911
+ }
912
+ set value(value) {
913
+ this._value = value;
914
+ }
915
+ get deltaTemplate() {
916
+ return this._deltaTemplate;
917
+ }
918
+ constructor() {
919
+ this.Math = Math;
920
+ this.Number = Number;
921
+ this.data = [];
922
+ this.index = 0;
923
+ this.classes = {
924
+ span: 'gt-delta',
925
+ positive: 'text-success',
926
+ negative: 'text-danger',
927
+ };
928
+ this.key = 'value';
929
+ this.notApplicableValue = null;
930
+ this.initialValue = null;
931
+ }
932
+ set deltaTemplate(deltaTemplate) {
933
+ this._deltaTemplate = deltaTemplate;
934
+ }
935
+ ngOnChanges(changes) {
936
+ if (!changes.data.currentValue) {
937
+ return;
938
+ }
939
+ const data = changes.data?.currentValue;
940
+ const index = changes.index?.currentValue || this.index;
941
+ const baseIndex = changes.baseIndex?.currentValue;
942
+ const key = changes.key?.currentValue || this.key;
943
+ const initialValue = changes.initialValue?.currentValue || this.initialValue;
944
+ const deltaValue = index === 0
945
+ ? initialValue
946
+ : data[index][key] -
947
+ (baseIndex === undefined
948
+ ? data[index - 1][key]
949
+ : data[baseIndex][key]);
950
+ const baseValue = index === 0
951
+ ? 1
952
+ : baseIndex === undefined
953
+ ? data[index - 1][key]
954
+ : data[baseIndex][key];
955
+ const relative = index === 0
956
+ ? initialValue
957
+ : Math.sign(deltaValue) * Math.abs(deltaValue / baseValue);
958
+ this.value = {
959
+ relative: Number.isFinite(relative)
960
+ ? relative
961
+ : index === 0
962
+ ? initialValue
963
+ : changes.notApplicableValue?.currentValue || this.notApplicableValue,
964
+ absolute: deltaValue,
965
+ };
966
+ }
967
+ }
968
+ GtDeltaComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: GtDeltaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
969
+ GtDeltaComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.1", type: GtDeltaComponent, isStandalone: true, selector: "gt-delta", inputs: { deltaTemplate: "deltaTemplate", data: "data", index: "index", baseIndex: "baseIndex", classes: "classes", key: "key", notApplicableValue: "notApplicableValue", initialValue: "initialValue" }, usesOnChanges: true, ngImport: i0, template: `<span
970
+ *ngIf="value as delta"
971
+ [class]="[
972
+ classes.span,
973
+ delta.absolute > 0
974
+ ? classes.positive
975
+ : delta.absolute < 0
976
+ ? classes.negative
977
+ : null
978
+ ]"
979
+ [class.gt-delta-positive]="delta.absolute > 0"
980
+ [class.gt-delta-negative]="delta.absolute < 0"
981
+ ><ng-container
982
+ *ngTemplateOutlet="deltaTemplate || defaultTemplate; context: { delta }"
983
+ ></ng-container>
984
+ </span>
985
+ <ng-template #defaultTemplate let-delta="delta">
986
+ <span *ngIf="delta.relative">{{
987
+ delta.relative | percent: '1.0-2'
988
+ }}</span>
989
+ </ng-template>`, isInline: true, styles: [":host{display:inline-block}\n"], dependencies: [{ kind: "pipe", type: PercentPipe, name: "percent" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
990
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: GtDeltaComponent, decorators: [{
991
+ type: Component,
992
+ args: [{ selector: 'gt-delta', template: `<span
993
+ *ngIf="value as delta"
994
+ [class]="[
995
+ classes.span,
996
+ delta.absolute > 0
997
+ ? classes.positive
998
+ : delta.absolute < 0
999
+ ? classes.negative
1000
+ : null
1001
+ ]"
1002
+ [class.gt-delta-positive]="delta.absolute > 0"
1003
+ [class.gt-delta-negative]="delta.absolute < 0"
1004
+ ><ng-container
1005
+ *ngTemplateOutlet="deltaTemplate || defaultTemplate; context: { delta }"
1006
+ ></ng-container>
1007
+ </span>
1008
+ <ng-template #defaultTemplate let-delta="delta">
1009
+ <span *ngIf="delta.relative">{{
1010
+ delta.relative | percent: '1.0-2'
1011
+ }}</span>
1012
+ </ng-template>`, changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [PercentPipe, NgIf, NgTemplateOutlet], styles: [":host{display:inline-block}\n"] }]
1013
+ }], ctorParameters: function () { return []; }, propDecorators: { deltaTemplate: [{
1014
+ type: Input
1015
+ }], data: [{
1016
+ type: Input
1017
+ }], index: [{
1018
+ type: Input
1019
+ }], baseIndex: [{
1020
+ type: Input
1021
+ }], classes: [{
1022
+ type: Input
1023
+ }], key: [{
1024
+ type: Input
1025
+ }], notApplicableValue: [{
1026
+ type: Input
1027
+ }], initialValue: [{
1028
+ type: Input
1029
+ }] } });
1030
+
1031
+ class GenericTableCoreModule {
1032
+ }
1033
+ GenericTableCoreModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: GenericTableCoreModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1034
+ GenericTableCoreModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.1.1", ngImport: i0, type: GenericTableCoreModule, imports: [CommonModule,
1035
+ CoreComponent,
1036
+ SortClassPipe,
1037
+ DashCasePipe,
1038
+ HighlightPipe,
1039
+ RowSelectionPipe,
1040
+ CapitalCasePipe,
1041
+ CapitalCasePipe,
1042
+ DynamicPipe,
1043
+ GtDeltaComponent], exports: [CoreComponent, GtDeltaComponent] });
1044
+ GenericTableCoreModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: GenericTableCoreModule, imports: [CommonModule,
1045
+ CoreComponent,
1046
+ GtDeltaComponent] });
1047
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: GenericTableCoreModule, decorators: [{
1048
+ type: NgModule,
1049
+ args: [{
1050
+ imports: [
1051
+ CommonModule,
1052
+ CoreComponent,
1053
+ SortClassPipe,
1054
+ DashCasePipe,
1055
+ HighlightPipe,
1056
+ RowSelectionPipe,
1057
+ CapitalCasePipe,
1058
+ CapitalCasePipe,
1059
+ DynamicPipe,
1060
+ GtDeltaComponent,
1061
+ ],
1062
+ exports: [CoreComponent, GtDeltaComponent],
1063
+ declarations: [],
1064
+ }]
1065
+ }] });
1066
+
1067
+ class PaginationComponent {
1068
+ constructor() {
1069
+ this._table$ = new ReplaySubject(1);
1070
+ this._ariaLabels = {
1071
+ nav: 'Table pagination',
1072
+ button: 'Go to page ',
1073
+ };
1074
+ this._classes = {
1075
+ ul: 'pagination',
1076
+ li: 'page-item',
1077
+ button: 'page-link',
1078
+ };
1079
+ this._paginationLength = 5;
1080
+ /** paginationListItems$ - observable for page numbers to show based on number of pages and current position */
1081
+ this.paginationListItems$ = this._table$.pipe(switchMap((core) => combineLatest([
1082
+ core?.table$.pipe(pluck('info')),
1083
+ core?.currentPaginationIndex$,
1084
+ ])), map(([info, currentPage]) => this._generateList(info.pageTotal, currentPage)), shareReplay(1));
1085
+ }
1086
+ get pagingInfo() {
1087
+ return (this._pagingInfo || {
1088
+ pageNext: null,
1089
+ pageCurrent: null,
1090
+ pagePrevious: null,
1091
+ pageSize: null,
1092
+ numberOfRecords: null,
1093
+ pageTotal: null,
1094
+ });
1095
+ }
1096
+ /** pagingInfo
1097
+ * @description when provided, pagination component will use this information to render pagination instead of data from table. Use this option when pagination is handled by backend (server side).
1098
+ * @type info - metadata for pagination component
1099
+ */
1100
+ set pagingInfo(info) {
1101
+ this._pagingInfo = info;
1102
+ }
1103
+ get paginationLength() {
1104
+ return this._paginationLength;
1105
+ }
1106
+ /** paginationLength
1107
+ * @description number of buttons to show in pagination
1108
+ * @type length - number of buttons to show. Defaults to: `5`
1109
+ */
1110
+ set paginationLength(length) {
1111
+ this._paginationLength = +length;
1112
+ }
1113
+ get classes() {
1114
+ return this._classes;
1115
+ }
1116
+ /** classes
1117
+ * @description classes that should be used within pagination component for different elements
1118
+ * @type classes - classes to be used. Defaults to: `{
1119
+ * ul: 'pagination',
1120
+ * li: 'page-item',
1121
+ * button: 'page-link',
1122
+ * }`
1123
+ */
1124
+ set classes(classes) {
1125
+ this._classes = classes;
1126
+ }
1127
+ get ariaLabels() {
1128
+ return this._ariaLabels;
1129
+ }
1130
+ /** ariaLabels
1131
+ * @description aria labels that describe pagination component
1132
+ * @type labels - aria labels for pagination. Defaults to: `{
1133
+ * nav: 'Table pagination',
1134
+ * button: 'Go to page ',
1135
+ * }`
1136
+ */
1137
+ set ariaLabels(labels) {
1138
+ this._ariaLabels = labels;
1139
+ }
1140
+ get table() {
1141
+ return this._table;
1142
+ }
1143
+ /** table
1144
+ * @description table component to which pagination is attached
1145
+ * @type tableRef - table component
1146
+ */
1147
+ set table(tableRef) {
1148
+ this._table = tableRef;
1149
+ this._table$.next(tableRef);
1150
+ }
1151
+ /** generate list - generate an array with page numbers to show based on number of pages and current position
1152
+ * @param numberOfPages number of pages to show
1153
+ * @param currentPosition current position (page index) being shown in table
1154
+ * @returns Array<number> array of page numbers to show
1155
+ */
1156
+ _generateList(numberOfPages, currentPosition) {
1157
+ const middle = Math.floor(this.paginationLength / 2);
1158
+ const length = numberOfPages < this.paginationLength
1159
+ ? numberOfPages
1160
+ : this.paginationLength;
1161
+ return Array.from({ length }, (_, i) => {
1162
+ if (i === 0) {
1163
+ return 1;
1164
+ }
1165
+ else if (numberOfPages < this.paginationLength) {
1166
+ return i + 1;
1167
+ }
1168
+ else if (i + 1 === length) {
1169
+ return numberOfPages;
1170
+ }
1171
+ else if (currentPosition > middle &&
1172
+ currentPosition < numberOfPages - middle) {
1173
+ return i + currentPosition - (middle - 1);
1174
+ }
1175
+ else if (currentPosition > middle &&
1176
+ currentPosition < numberOfPages - (middle - 1)) {
1177
+ return i + currentPosition - middle;
1178
+ }
1179
+ else if (currentPosition > middle &&
1180
+ currentPosition === numberOfPages - (middle - 1)) {
1181
+ return i + currentPosition - (middle + 1);
1182
+ }
1183
+ else if (currentPosition > middle &&
1184
+ currentPosition === numberOfPages - 1) {
1185
+ return i + currentPosition - (middle + 2);
1186
+ }
1187
+ else {
1188
+ return i + 1;
1189
+ }
1190
+ });
1191
+ }
1192
+ /** go to page
1193
+ * @param index - page index to go to
1194
+ */
1195
+ goToPage(index) {
1196
+ if (this.table) {
1197
+ this.table.paginationIndex = index - 1;
1198
+ }
1199
+ }
1200
+ }
1201
+ PaginationComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: PaginationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1202
+ PaginationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.1.1", type: PaginationComponent, isStandalone: true, selector: "angular-generic-table-pagination", inputs: { pagingInfo: "pagingInfo", paginationLength: "paginationLength", classes: "classes", ariaLabels: "ariaLabels", table: "table" }, ngImport: i0, template: "<ng-container\n *ngIf=\"{\n links: paginationListItems$ | async,\n currentPosition: table?.currentPaginationIndex$ | async\n } as pagination\"\n>\n <nav\n *ngIf=\"pagination.links && pagination.links.length > 1\"\n role=\"navigation\"\n [attr.aria-label]=\"ariaLabels.nav\"\n class=\"gt-pagination\"\n [class]=\"classes.nav\"\n >\n <ul [class]=\"classes.ul\">\n <ng-container\n *ngFor=\"\n let position of pagination!.links;\n let i = index;\n let last = last\n \"\n >\n <li\n [class]=\"classes.li\"\n [class.active]=\"position === (pagination!.currentPosition || 0) + 1\"\n >\n <button\n [class]=\"classes.button\"\n [attr.aria-label]=\"ariaLabels.button + position\"\n (click)=\"goToPage(position)\"\n >\n {{ position }}\n </button>\n </li>\n <li\n [class]=\"classes.li\"\n class=\"gt-ellipsis\"\n *ngIf=\"position + 1 !== pagination!.links![i + 1] && !last\"\n >\n <button [class]=\"classes.button\" disabled tabindex=\"-1\"></button>\n </li>\n </ng-container>\n </ul>\n </nav>\n</ng-container>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1203
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: PaginationComponent, decorators: [{
1204
+ type: Component,
1205
+ args: [{ selector: 'angular-generic-table-pagination', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule], template: "<ng-container\n *ngIf=\"{\n links: paginationListItems$ | async,\n currentPosition: table?.currentPaginationIndex$ | async\n } as pagination\"\n>\n <nav\n *ngIf=\"pagination.links && pagination.links.length > 1\"\n role=\"navigation\"\n [attr.aria-label]=\"ariaLabels.nav\"\n class=\"gt-pagination\"\n [class]=\"classes.nav\"\n >\n <ul [class]=\"classes.ul\">\n <ng-container\n *ngFor=\"\n let position of pagination!.links;\n let i = index;\n let last = last\n \"\n >\n <li\n [class]=\"classes.li\"\n [class.active]=\"position === (pagination!.currentPosition || 0) + 1\"\n >\n <button\n [class]=\"classes.button\"\n [attr.aria-label]=\"ariaLabels.button + position\"\n (click)=\"goToPage(position)\"\n >\n {{ position }}\n </button>\n </li>\n <li\n [class]=\"classes.li\"\n class=\"gt-ellipsis\"\n *ngIf=\"position + 1 !== pagination!.links![i + 1] && !last\"\n >\n <button [class]=\"classes.button\" disabled tabindex=\"-1\"></button>\n </li>\n </ng-container>\n </ul>\n </nav>\n</ng-container>\n" }]
1206
+ }], propDecorators: { pagingInfo: [{
1207
+ type: Input
1208
+ }], paginationLength: [{
1209
+ type: Input
1210
+ }], classes: [{
1211
+ type: Input
1212
+ }], ariaLabels: [{
1213
+ type: Input
1214
+ }], table: [{
1215
+ type: Input
1216
+ }] } });
1217
+
1218
+ class GenericTablePaginationModule {
1219
+ }
1220
+ GenericTablePaginationModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: GenericTablePaginationModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1221
+ GenericTablePaginationModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.1.1", ngImport: i0, type: GenericTablePaginationModule, imports: [CommonModule, PaginationComponent], exports: [PaginationComponent] });
1222
+ GenericTablePaginationModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: GenericTablePaginationModule, imports: [CommonModule, PaginationComponent] });
1223
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.1.1", ngImport: i0, type: GenericTablePaginationModule, decorators: [{
1224
+ type: NgModule,
1225
+ args: [{
1226
+ imports: [CommonModule, PaginationComponent],
1227
+ exports: [PaginationComponent],
1228
+ }]
1229
+ }] });
1230
+
1231
+ /*
1232
+ * Public API Surface of core
1233
+ */
1234
+
1235
+ /**
1236
+ * Generated bundle index. Do not edit.
1237
+ */
1238
+
1239
+ export { CapitalCasePipe, CoreComponent, CoreService, DashCasePipe, DynamicPipe, GenericTableCoreModule, GenericTablePaginationModule, GtDeltaComponent, HighlightPipe, PaginationComponent, SortClassPipe, calculate, capitalize, chunk, dashed, parseSortOrderParams, search, sortOnMultipleKeys, sortOrderConfigToParam, sortOrderToParams };
1240
+ //# sourceMappingURL=angular-generic-table-core.mjs.map