@triptyk/ember-yeti-table 3.0.0

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 (89) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +132 -0
  3. package/addon-main.cjs +4 -0
  4. package/declarations/themes/default-theme.d.ts +28 -0
  5. package/declarations/themes/default-theme.d.ts.map +1 -0
  6. package/declarations/utils/create-regex.d.ts +2 -0
  7. package/declarations/utils/create-regex.d.ts.map +1 -0
  8. package/declarations/utils/filtering-utils.d.ts +5 -0
  9. package/declarations/utils/filtering-utils.d.ts.map +1 -0
  10. package/declarations/utils/sorting-utils.d.ts +24 -0
  11. package/declarations/utils/sorting-utils.d.ts.map +1 -0
  12. package/dist/_app_/components/yeti-table/body.js +1 -0
  13. package/dist/_app_/components/yeti-table/header.js +1 -0
  14. package/dist/_app_/components/yeti-table/pagination.js +1 -0
  15. package/dist/_app_/components/yeti-table/table.js +1 -0
  16. package/dist/_app_/components/yeti-table/tbody/row/cell.js +1 -0
  17. package/dist/_app_/components/yeti-table/tbody/row.js +1 -0
  18. package/dist/_app_/components/yeti-table/tbody.js +1 -0
  19. package/dist/_app_/components/yeti-table/tfoot/row/cell.js +1 -0
  20. package/dist/_app_/components/yeti-table/tfoot/row.js +1 -0
  21. package/dist/_app_/components/yeti-table/tfoot.js +1 -0
  22. package/dist/_app_/components/yeti-table/thead/row/cell.js +1 -0
  23. package/dist/_app_/components/yeti-table/thead/row/column.js +1 -0
  24. package/dist/_app_/components/yeti-table/thead/row.js +1 -0
  25. package/dist/_app_/components/yeti-table/thead.js +1 -0
  26. package/dist/_app_/components/yeti-table.js +1 -0
  27. package/dist/_app_/themes/default-theme.js +1 -0
  28. package/dist/_app_/utils/create-regex.js +1 -0
  29. package/dist/_app_/utils/filtering-utils.js +1 -0
  30. package/dist/_app_/utils/sorting-utils.js +1 -0
  31. package/dist/components/yeti-table/body.js +37 -0
  32. package/dist/components/yeti-table/body.js.map +1 -0
  33. package/dist/components/yeti-table/header.js +30 -0
  34. package/dist/components/yeti-table/header.js.map +1 -0
  35. package/dist/components/yeti-table/pagination.js +86 -0
  36. package/dist/components/yeti-table/pagination.js.map +1 -0
  37. package/dist/components/yeti-table/table.js +38 -0
  38. package/dist/components/yeti-table/table.js.map +1 -0
  39. package/dist/components/yeti-table/tbody/row/cell.js +35 -0
  40. package/dist/components/yeti-table/tbody/row/cell.js.map +1 -0
  41. package/dist/components/yeti-table/tbody/row.js +47 -0
  42. package/dist/components/yeti-table/tbody/row.js.map +1 -0
  43. package/dist/components/yeti-table/tbody.js +20 -0
  44. package/dist/components/yeti-table/tbody.js.map +1 -0
  45. package/dist/components/yeti-table/tfoot/row/cell.js +31 -0
  46. package/dist/components/yeti-table/tfoot/row/cell.js.map +1 -0
  47. package/dist/components/yeti-table/tfoot/row.js +31 -0
  48. package/dist/components/yeti-table/tfoot/row.js.map +1 -0
  49. package/dist/components/yeti-table/tfoot.js +20 -0
  50. package/dist/components/yeti-table/tfoot.js.map +1 -0
  51. package/dist/components/yeti-table/thead/row/cell.js +24 -0
  52. package/dist/components/yeti-table/thead/row/cell.js.map +1 -0
  53. package/dist/components/yeti-table/thead/row/column.js +202 -0
  54. package/dist/components/yeti-table/thead/row/column.js.map +1 -0
  55. package/dist/components/yeti-table/thead/row.js +41 -0
  56. package/dist/components/yeti-table/thead/row.js.map +1 -0
  57. package/dist/components/yeti-table/thead.js +35 -0
  58. package/dist/components/yeti-table/thead.js.map +1 -0
  59. package/dist/components/yeti-table.js +618 -0
  60. package/dist/components/yeti-table.js.map +1 -0
  61. package/dist/themes/default-theme.js +51 -0
  62. package/dist/themes/default-theme.js.map +1 -0
  63. package/dist/utils/create-regex.js +34 -0
  64. package/dist/utils/create-regex.js.map +1 -0
  65. package/dist/utils/filtering-utils.js +55 -0
  66. package/dist/utils/filtering-utils.js.map +1 -0
  67. package/dist/utils/sorting-utils.js +93 -0
  68. package/dist/utils/sorting-utils.js.map +1 -0
  69. package/package.json +124 -0
  70. package/src/.gitkeep +0 -0
  71. package/src/components/yeti-table/body.gjs +94 -0
  72. package/src/components/yeti-table/header.gjs +54 -0
  73. package/src/components/yeti-table/pagination.gjs +155 -0
  74. package/src/components/yeti-table/table.gjs +34 -0
  75. package/src/components/yeti-table/tbody/row/cell.gjs +51 -0
  76. package/src/components/yeti-table/tbody/row.gjs +89 -0
  77. package/src/components/yeti-table/tbody.gjs +55 -0
  78. package/src/components/yeti-table/tfoot/row/cell.gjs +45 -0
  79. package/src/components/yeti-table/tfoot/row.gjs +44 -0
  80. package/src/components/yeti-table/tfoot.gjs +33 -0
  81. package/src/components/yeti-table/thead/row/cell.gjs +52 -0
  82. package/src/components/yeti-table/thead/row/column.gjs +260 -0
  83. package/src/components/yeti-table/thead/row.gjs +71 -0
  84. package/src/components/yeti-table/thead.gjs +45 -0
  85. package/src/components/yeti-table.gjs +780 -0
  86. package/src/themes/default-theme.js +53 -0
  87. package/src/utils/create-regex.js +65 -0
  88. package/src/utils/filtering-utils.js +75 -0
  89. package/src/utils/sorting-utils.js +108 -0
@@ -0,0 +1,618 @@
1
+ import { getOwner } from '@ember/application';
2
+ import { action, notifyPropertyChange } from '@ember/object';
3
+ import { scheduleOnce, later, schedule } from '@ember/runloop';
4
+ import { isPresent, isEmpty } from '@ember/utils';
5
+ import Component from '@glimmer/component';
6
+ import { cached, tracked } from '@glimmer/tracking';
7
+ import merge from 'deepmerge';
8
+ import { use } from 'ember-resources';
9
+ import { trackedFunction } from 'reactiveweb/function';
10
+ import { keepLatest } from 'reactiveweb/keep-latest';
11
+ import { localCopy, dedupeTracked } from 'tracked-toolbox';
12
+ import DEFAULT_THEME from '../themes/default-theme.js';
13
+ import filterData from '../utils/filtering-utils.js';
14
+ import { sortMultiple, compareValues, mergeSort } from '../utils/sorting-utils.js';
15
+ import Helper from '@ember/component/helper';
16
+ import { hash } from '@ember/helper';
17
+ import Table from './yeti-table/table.js';
18
+ import Header from './yeti-table/header.js';
19
+ import THead from './yeti-table/thead.js';
20
+ import Body from './yeti-table/body.js';
21
+ import TBody from './yeti-table/tbody.js';
22
+ import TFoot from './yeti-table/tfoot.js';
23
+ import Pagination from './yeti-table/pagination.js';
24
+ import { precompileTemplate } from '@ember/template-compilation';
25
+ import { setComponentTemplate } from '@ember/component';
26
+ import { g, i, n } from 'decorator-transforms/runtime-esm';
27
+
28
+ const TASK_CANCELATION_NAME = 'TaskCancelation';
29
+ const didCancel = function (e) {
30
+ return e && e.name === TASK_CANCELATION_NAME;
31
+ };
32
+ const getConfigWithDefault = function (key, defaultValue) {
33
+ return function () {
34
+ return this.config[key] ?? defaultValue;
35
+ };
36
+ };
37
+ // we keep `totalRows` updated manually in xwaan untracked property
38
+ // to allow the user to update it in a loadData call and avoid
39
+ // a re-run of the main tracked function
40
+ class UpdateTotalRows extends Helper {
41
+ compute(positional, {
42
+ context
43
+ }) {
44
+ context.totalRows = positional[0];
45
+ notifyPropertyChange(context, 'normalizedTotalRows');
46
+ notifyPropertyChange(context, 'paginationData');
47
+ return '';
48
+ }
49
+ }
50
+ // we need some control of how we update the filter property, hence this modifier
51
+ // in this case, any falsy value will be considered as en empty string, which will then
52
+ // be deduped.
53
+ class UpdateFilter extends Helper {
54
+ compute(positional, {
55
+ context
56
+ }) {
57
+ context.filter = positional[0] || '';
58
+ return '';
59
+ }
60
+ }
61
+ class ProcessedData extends Helper {
62
+ compute(positional, {
63
+ loadData,
64
+ context
65
+ }) {
66
+ let data = context.latestData ?? [];
67
+ if (!loadData) {
68
+ context.processData(data);
69
+ } else {
70
+ // This is instrumental to ignoreDataChanges working
71
+ context.processedData = data;
72
+ }
73
+ return '';
74
+ }
75
+ }
76
+ class YetiTable extends Component {
77
+ static {
78
+ setComponentTemplate(precompileTemplate("{{#let (hash table=(component Table theme=this.mergedTheme parent=this) header=(component Header columns=this.columns onColumnClick=this.onColumnSort sortable=this.sortable sortSequence=this.sortSequence parent=this theme=this.mergedTheme) thead=(component THead columns=this.columns onColumnClick=this.onColumnSort sortable=this.sortable sortSequence=this.sortSequence theme=this.mergedTheme parent=this) body=(component Body data=this.processedData columns=this.columns theme=this.mergedTheme parent=this) tbody=(component TBody data=this.processedData columns=this.columns theme=this.mergedTheme parent=this) tfoot=(component TFoot columns=this.columns theme=this.mergedTheme parent=this) pagination=(component Pagination disabled=this.isLoading theme=this.mergedTheme paginationData=this.paginationData paginationActions=(hash previousPage=this.previousPage nextPage=this.nextPage goToPage=this.goToPage changePageSize=this.changePageSize)) actions=this.publicApi paginationData=this.paginationData isLoading=this.resolvedData.isPending columns=this.columns visibleColumns=this.visibleColumns rows=this.normalizedRows totalRows=this.normalizedTotalRows visibleRows=this.processedData theme=this.mergedTheme) as |api|}}\n {{UpdateTotalRows @totalRows context=this}}\n {{UpdateFilter @filter context=this}}\n {{ProcessedData loadData=@loadData context=this}}\n\n {{#if this.renderTableElement}}\n <Table @theme={{this.mergedTheme}} @parent={{this}} ...attributes>\n {{yield api}}\n </Table>\n {{else}}\n {{yield api}}\n {{/if}}\n\n{{/let}}", {
79
+ strictMode: true,
80
+ scope: () => ({
81
+ hash,
82
+ Table,
83
+ Header,
84
+ THead,
85
+ Body,
86
+ TBody,
87
+ TFoot,
88
+ Pagination,
89
+ UpdateTotalRows,
90
+ UpdateFilter,
91
+ ProcessedData
92
+ })
93
+ }), this);
94
+ }
95
+ /**
96
+ * An object that contains classes for yeti table to apply when rendering its various table
97
+ * html elements. The theme object your pass in will be deeply merged with yeti-table's default theme
98
+ * and with a theme defined in your environment.js at `ENV['ember-yeti-table'].theme`.
99
+ *
100
+ * @argument theme
101
+ * @type {Object}
102
+ */ /**
103
+ * The data for Yeti Table to render. It can be an array or a promise that resolves with an array.
104
+ * The only case when `@data` is optional is if a `@loadData` was passed in.
105
+ * @argument data
106
+ * @type {Array | Promise<Array>}
107
+ */ /**
108
+ * The function that will be called when Yeti Table needs data. This argument is used
109
+ * when you don't have all the data available or loading all rows at once isn't possible,
110
+ * e.g the dataset is too large.
111
+ *
112
+ * By passing in a function to `@loadData` you assume the responsibility to filter, sort and
113
+ * paginate the data (if said features are enabled).
114
+ *
115
+ * This function must return an array or a promise that resolves with an array.
116
+ *
117
+ * This function will be called with an argument with the current state of the table.
118
+ * Use this object to know what data to fetch, pass it to the server, etc.
119
+ * Please check the "Async Data" guide to understand what that object contains and
120
+ * an example of its usage.
121
+ *
122
+ * @argument loadData
123
+ * @type {Function}
124
+ */
125
+ publicApi = {
126
+ previousPage: this.previousPage,
127
+ nextPage: this.nextPage,
128
+ goToPage: this.goToPage,
129
+ changePageSize: this.changePageSize,
130
+ reloadData: this.reloadData
131
+ };
132
+ /**
133
+ * This function will be called when Yeti Table initializes. It will be called with
134
+ * an object argument containing the functions for the possible actions you can make
135
+ * on a table. This object contains the following actions:
136
+ * - previousPage
137
+ * - nextPage
138
+ * - goToPage
139
+ * - changePageSize
140
+ * - reloadData
141
+ *
142
+ * @argument registerApi
143
+ * @type {Function}
144
+ */ /**
145
+ * Use this argument to enable the pagination feature. Default is `false`.
146
+ *
147
+ * @argument pagination
148
+ * @type {Boolean}
149
+ */
150
+ static {
151
+ g(this.prototype, "pagination", [localCopy('args.pagination', getConfigWithDefault('pagination', false))]);
152
+ }
153
+ #pagination = (i(this, "pagination"), void 0);
154
+ static {
155
+ g(this.prototype, "pageSize", [localCopy('args.pageSize', getConfigWithDefault('pageSize', 15))]);
156
+ }
157
+ #pageSize = (i(this, "pageSize"), void 0);
158
+ /**
159
+ * Controls the size of each page. Default is `15`.
160
+ *
161
+ * @argument pageSize
162
+ * @type {number}
163
+ */
164
+ static {
165
+ g(this.prototype, "pageNumber", [localCopy('args.pageNumber', 1)]);
166
+ }
167
+ #pageNumber = (i(this, "pageNumber"), void 0);
168
+ /**
169
+ * Controls the current page to show. Default is `1`.
170
+ *
171
+ * @argument pageNumber
172
+ * @type {number}
173
+ */
174
+ /**
175
+ * Optional argument that informs yeti table of how many rows your data has.
176
+ * Only needed when using a `@loadData` function and `@pagination={{true}}`.
177
+ * When you use `@data`, Yeti Table uses the size of that array.
178
+ * This information is used to calculate the pagination information that is yielded
179
+ * and passed to the `@loadData` function.
180
+ *
181
+ * @argument totalRows
182
+ * @type {number}
183
+ */
184
+ totalRows;
185
+ // we keep `totalRows` updated manually in an untracked property
186
+ // to allow the user to update it in a loadData call and avoid
187
+ // a re-run of the main tracked function
188
+ // @action
189
+ // updateTotalRows(totalRows) {
190
+ // this.totalRows = totalRows;
191
+ // notifyPropertyChange(this, 'normalizedTotalRows');
192
+ // notifyPropertyChange(this, 'paginationData');
193
+ // }
194
+ /**
195
+ * The global filter. If passed in, Yeti Table will search all the rows that contain this
196
+ * string and show them. Defaults to `''`.
197
+ *
198
+ * @argument filter
199
+ * @type {String}
200
+ */
201
+ static {
202
+ g(this.prototype, "filter", [dedupeTracked], function () {
203
+ return '';
204
+ });
205
+ }
206
+ #filter = (i(this, "filter"), void 0);
207
+ static {
208
+ g(this.prototype, "sortable", [localCopy('args.sortable', getConfigWithDefault('sortable', true))]);
209
+ }
210
+ #sortable = (i(this, "sortable"), void 0); // we need some control of how we update the filter property, hence this modifier
211
+ // in this case, any falsy value will be considered as en empty string, which will then
212
+ // be deduped.
213
+ // @action
214
+ // updateFilter(filter) {
215
+ // this.filter = filter || '';
216
+ // }
217
+ /**
218
+ * An optional function to customize the filtering logic. This function should return true
219
+ * or false to either include or exclude the row on the resulting set. If this function depends
220
+ * on a value, pass that value as the `@filterUsing` argument.
221
+ *
222
+ * This function will be called with two arguments:
223
+ * - `row` - the current data row to use for filtering
224
+ * - `filterUsing` - the value you passed in as `@filterUsing`
225
+ *
226
+ * @argument filterFunction
227
+ * @type {Function}
228
+ */
229
+ /**
230
+ * If you `@filterFunction` function depends on a different value (other that `@filter`)
231
+ * to show, pass it in this argument. Yeti Table uses this argument to know when to recalculate
232
+ * the fitlered rows.
233
+ *
234
+ * @argument filterUsing
235
+ * @type {Object}
236
+ */
237
+ /**
238
+ * Used to enable/disable sorting on all columns. You should use this to avoid passing
239
+ * the @sortable argument to all columns. Defaults to `true`.
240
+ *
241
+ * @argument sortable
242
+ * @type {Boolean}
243
+ */
244
+ static {
245
+ g(this.prototype, "sortFunction", [localCopy('args.sortFunction', () => sortMultiple)]);
246
+ }
247
+ #sortFunction = (i(this, "sortFunction"), void 0);
248
+ /**
249
+ * Use the `@sortFunction` if you want to completely customize how the row sorting is done.
250
+ * It will be invoked with two rows, the current sortings that are applied and the `@compareFunction`.
251
+ *
252
+ * @argument sortFunction
253
+ * @type {Function}
254
+ */
255
+ static {
256
+ g(this.prototype, "compareFunction", [localCopy('args.compareFunction', () => compareValues)]);
257
+ }
258
+ #compareFunction = (i(this, "compareFunction"), void 0);
259
+ /**
260
+ * Use `@compareFunction` if you just want to customize how two values relate to each other (not the entire row).
261
+ * It will be invoked with two values and you just need to return `-1`, `0` or `1` depending on if first value is
262
+ * greater than the second or not. The default compare function used is the `compare` function from `@ember/utils`.
263
+ *
264
+ * @argument compareFunction
265
+ * @type {Function}
266
+ */
267
+ static {
268
+ g(this.prototype, "sortSequence", [localCopy('args.sortSequence', getConfigWithDefault('sortSequence', ['asc', 'desc']))]);
269
+ }
270
+ #sortSequence = (i(this, "sortSequence"), void 0);
271
+ /**
272
+ * Use `@sortSequence` to customize the sequence in which the sorting order will cycle when
273
+ * clicking on the table headers. You can either pass in a comma-separated string or an array
274
+ * of strings. Accepted values are `'asc'`, `'desc'` and `'unsorted'`. The default value is `['asc', 'desc']`.
275
+ *
276
+ * @argument sortSequence
277
+ * @type {Array<string> | string}
278
+ */
279
+ static {
280
+ g(this.prototype, "ignoreDataChanges", [localCopy('args.ignoreDataChanges', getConfigWithDefault('ignoreDataChanges', false))]);
281
+ }
282
+ #ignoreDataChanges = (i(this, "ignoreDataChanges"), void 0);
283
+ /**
284
+ * Use `@ignoreDataChanges` to prevent yeti table from observing changes to the underlying data and resorting or
285
+ * refiltering. Useful when doing inline editing in a table.
286
+ *
287
+ * Defaults to `false`.
288
+ *
289
+ * This is an initial render only value. Changing it after the table has been rendered will not be respected.
290
+ *
291
+ * @argument ignoreDataChanges
292
+ * @type {boolean}
293
+ */
294
+ static {
295
+ g(this.prototype, "renderTableElement", [localCopy('args.renderTableElement', true)]);
296
+ }
297
+ #renderTableElement = (i(this, "renderTableElement"), void 0);
298
+ /**
299
+ * Use `@renderTableElement` to prevent yeti table from rendering the topmost <table> element.
300
+ * Might be useful for styling purposes (e.g if you want to place your pagination controls outside
301
+ * of your table element). If you set this to `false`, you should render the table element yourself
302
+ * using the yielded `<t.table>` component.
303
+ *
304
+ * Defaults to `true`.
305
+ *
306
+ * @argument renderTableElement
307
+ * @type {boolean}
308
+ */
309
+ /**
310
+ * The `@isColumnVisible` argument can be used to initialize the column visibility in a programmatic way.
311
+ * For example, let's say you store the initial column visibility in local storage, then you can
312
+ * use this function to initialize the `visible` column of the specific column. The given function should
313
+ * return a boolean which will be assigned to the `visible` property of the column. An object representing
314
+ * the column is passed in. Sou can use column.prop and column.name to know which column your computed
315
+ * the visibility for.
316
+ *
317
+ * @argument isColumnVisible
318
+ * @type {Function}
319
+ */ // If the theme is replaced, this will invalidate, but not if any prop under theme is changed
320
+ get mergedTheme() {
321
+ let configTheme = this.config.theme || {};
322
+ let localTheme = this.args.theme || {};
323
+ return merge.all([DEFAULT_THEME, configTheme, localTheme]);
324
+ }
325
+ static {
326
+ n(this.prototype, "mergedTheme", [cached]);
327
+ }
328
+ get visibleColumns() {
329
+ return this.columns.filter(c => c.visible === true);
330
+ }
331
+ static {
332
+ n(this.prototype, "visibleColumns", [cached]);
333
+ }
334
+ config = getOwner(this).resolveRegistration('config:environment')['ember-yeti-table'] || {};
335
+ get normalizedTotalRows() {
336
+ if (!this.args.loadData) {
337
+ // sync scenario using @data
338
+ return this.processedDataRows?.length || 0;
339
+ } else {
340
+ // async scenario. @loadData is present.
341
+ if (this.totalRows === undefined) {
342
+ // @totalRows was not passed in. Use the latest returned data set length as a fallback
343
+ return this.previousResolvedData.length || 0;
344
+ } else {
345
+ // @totalRows was passed in.
346
+ return this.totalRows;
347
+ }
348
+ }
349
+ }
350
+ get normalizedRows() {
351
+ if (!this.args.loadData) {
352
+ // sync scenario using @data
353
+ return this.processedDataRows;
354
+ } else {
355
+ // async scenario. @loadData is present.
356
+ return this.processedData;
357
+ }
358
+ }
359
+ get paginationData() {
360
+ let pageSize = this.pageSize;
361
+ let pageNumber = this.pageNumber;
362
+ let totalRows = this.normalizedTotalRows;
363
+ let isLastPage, totalPages;
364
+ if (totalRows) {
365
+ totalPages = Math.ceil(totalRows / pageSize);
366
+ pageNumber = Math.min(pageNumber, totalPages);
367
+ isLastPage = pageNumber === totalPages;
368
+ }
369
+ let isFirstPage = pageNumber === 1;
370
+ let pageStart = (pageNumber - 1) * pageSize + 1;
371
+ let pageEnd = pageStart + pageSize - 1;
372
+ if (totalRows) {
373
+ pageEnd = Math.min(pageEnd, totalRows);
374
+ }
375
+ return {
376
+ pageSize,
377
+ pageNumber,
378
+ pageStart,
379
+ pageEnd,
380
+ isFirstPage,
381
+ isLastPage,
382
+ totalRows,
383
+ totalPages
384
+ };
385
+ }
386
+ static {
387
+ g(this.prototype, "columns", [tracked], function () {
388
+ return [];
389
+ });
390
+ }
391
+ #columns = (i(this, "columns"), void 0);
392
+ constructor(owner, args) {
393
+ super(...arguments);
394
+ console.log(owner, args);
395
+ if (typeof this.args.registerApi === 'function') {
396
+ // eslint-disable-next-line ember/no-runloop
397
+ scheduleOnce('actions', null, this.args.registerApi, this.publicApi);
398
+ }
399
+ }
400
+ previousResolvedData = [];
401
+ resolvedData = trackedFunction(this, async () => {
402
+ let data = this.args.data;
403
+ if (this.columns.length == 0) {
404
+ return [];
405
+ }
406
+ // call loadData if exists
407
+ if (typeof this.args.loadData === 'function') {
408
+ let params = this.computeLoadDataParams();
409
+ try {
410
+ console.log("loadData", params);
411
+ data = await this.args.loadData(params);
412
+ console.log("loadData end");
413
+ } catch (e) {
414
+ console.log(e);
415
+ if (!didCancel(e)) {
416
+ // re-throw the non-cancellation error
417
+ throw e;
418
+ }
419
+ }
420
+ } else if (data?.then) {
421
+ // resolve the data promise (either from the @loadData call or @data)
422
+ data = await data;
423
+ }
424
+ if (this.isDestroyed) {
425
+ return;
426
+ }
427
+ data = data || [];
428
+ this.previousResolvedData = data;
429
+ return data;
430
+ });
431
+ static {
432
+ g(this.prototype, "latestData", [use], function () {
433
+ return keepLatest({
434
+ value: () => this.resolvedData.value ?? [],
435
+ when: () => this.resolvedData.isPending
436
+ });
437
+ });
438
+ }
439
+ #latestData = (i(this, "latestData"), void 0);
440
+ static {
441
+ g(this.prototype, "processedData", [tracked]);
442
+ }
443
+ #processedData = (i(this, "processedData"), void 0);
444
+ static {
445
+ g(this.prototype, "processedDataRows", [tracked]);
446
+ }
447
+ #processedDataRows = (i(this, "processedDataRows"), void 0);
448
+ processData(data) {
449
+ // only columns that have filterable = true and a prop defined will be considered
450
+ let columns = this.columns.filter(c => c.filterable && isPresent(c.prop));
451
+ let sortableColumns = this.columns.filter(c => !isEmpty(c.sort));
452
+ let sortings = sortableColumns.map(c => ({
453
+ prop: c.prop,
454
+ direction: c.sort
455
+ }));
456
+ let filterFunction = this.args.filterFunction;
457
+ let filterUsing = this.args.filterUsing;
458
+ let filter = this.filter;
459
+ let processTheData = () => {
460
+ // filter the data
461
+ data = filterData(data, columns, filter, filterFunction, filterUsing);
462
+ // Sort the data
463
+ if (sortings.length > 0) {
464
+ data = mergeSort(data, (itemA, itemB) => {
465
+ return this.sortFunction(itemA, itemB, sortings, this.compareFunction);
466
+ });
467
+ }
468
+ this.processedDataRows = data;
469
+ // Paginate the Data
470
+ if (this.pagination) {
471
+ let {
472
+ pageStart,
473
+ pageEnd
474
+ } = this.paginationData;
475
+ data = data.slice(pageStart - 1, pageEnd); // slice excludes last element so we don't need to subtract 1
476
+ }
477
+ this.processedData = data;
478
+ };
479
+ if (this.ignoreDataChanges) {
480
+ // eslint-disable-next-line ember/no-runloop
481
+ later(processTheData, 0);
482
+ } else {
483
+ processTheData();
484
+ }
485
+ }
486
+ computeLoadDataParams() {
487
+ let params = {};
488
+ if (this.pagination) {
489
+ params.paginationData = this.paginationData;
490
+ }
491
+ params.sortData = this.columns.filter(c => !isEmpty(c.sort)).map(c => ({
492
+ prop: c.prop,
493
+ direction: c.sort
494
+ }));
495
+ params.filterData = {
496
+ filter: this.filter,
497
+ filterUsing: this.args.filterUsing,
498
+ columnFilters: this.columns.map(c => ({
499
+ prop: c.prop,
500
+ filter: c.filter,
501
+ filterUsing: c.filterUsing
502
+ }))
503
+ };
504
+ return params;
505
+ }
506
+ paginateData(data) {
507
+ if (this.pagination) {
508
+ let {
509
+ pageStart,
510
+ pageEnd
511
+ } = this.paginationData;
512
+ data = data.slice(pageStart - 1, pageEnd); // slice excludes last element so we don't need to subtract 1
513
+ }
514
+ return data;
515
+ }
516
+ async reloadData() {
517
+ return await this.resolvedData.retry();
518
+ }
519
+ static {
520
+ n(this.prototype, "reloadData", [action]);
521
+ }
522
+ onColumnSort(column, e) {
523
+ if (column.isSorted) {
524
+ // if this column is already sorted, calculate the next
525
+ // sorting on the sequence.
526
+ let direction = column.sort;
527
+ let sortSequence = column.normalizedSortSequence;
528
+ direction = sortSequence[(sortSequence.indexOf(direction) + 1) % sortSequence.length];
529
+ if (direction === 'unsorted') {
530
+ direction = null;
531
+ }
532
+ column.sort = direction;
533
+ if (!e.shiftKey) {
534
+ // if not pressed shift, reset other column sorting
535
+ let columns = this.columns.filter(c => c !== column);
536
+ columns.forEach(c => c.sort = null);
537
+ }
538
+ } else {
539
+ // use first direction from sort sequence
540
+ let direction = column.normalizedSortSequence[0];
541
+ // create new sorting
542
+ column.sort = direction;
543
+ // normal click replaces all sortings with the new one
544
+ // shift click adds a new sorting to the existing ones
545
+ if (!e.shiftKey) {
546
+ // if not pressed shift, reset other column sortings
547
+ let columns = this.columns.filter(c => c !== column);
548
+ columns.forEach(c => c.sort = null);
549
+ }
550
+ }
551
+ }
552
+ static {
553
+ n(this.prototype, "onColumnSort", [action]);
554
+ }
555
+ previousPage() {
556
+ if (this.pagination) {
557
+ this.pageNumber = Math.max(this.pageNumber - 1, 1);
558
+ }
559
+ }
560
+ static {
561
+ n(this.prototype, "previousPage", [action]);
562
+ }
563
+ nextPage() {
564
+ if (this.pagination) {
565
+ let {
566
+ isLastPage
567
+ } = this.paginationData;
568
+ if (!isLastPage) {
569
+ this.pageNumber = this.pageNumber + 1;
570
+ }
571
+ }
572
+ }
573
+ static {
574
+ n(this.prototype, "nextPage", [action]);
575
+ }
576
+ goToPage(pageNumber) {
577
+ if (this.pagination) {
578
+ let {
579
+ totalPages
580
+ } = this.paginationData;
581
+ pageNumber = Math.max(pageNumber, 1);
582
+ if (totalPages) {
583
+ pageNumber = Math.min(pageNumber, totalPages);
584
+ }
585
+ this.pageNumber = pageNumber;
586
+ }
587
+ }
588
+ static {
589
+ n(this.prototype, "goToPage", [action]);
590
+ }
591
+ changePageSize(pageSize) {
592
+ if (this.pagination) {
593
+ this.pageSize = parseInt(pageSize);
594
+ }
595
+ }
596
+ static {
597
+ n(this.prototype, "changePageSize", [action]);
598
+ }
599
+ registerColumn(column) {
600
+ // eslint-disable-next-line ember/no-runloop
601
+ schedule('afterRender', this, function () {
602
+ if (typeof this.args.isColumnVisible === 'function') {
603
+ column.visible = this.args.isColumnVisible(column);
604
+ }
605
+ if (!this.columns.includes(column)) {
606
+ this.columns = [...this.columns, column];
607
+ }
608
+ });
609
+ }
610
+ unregisterColumn(column) {
611
+ if (this.columns.includes(column)) {
612
+ this.columns = this.columns.filter(c => c !== column);
613
+ }
614
+ }
615
+ }
616
+
617
+ export { YetiTable as default };
618
+ //# sourceMappingURL=yeti-table.js.map