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