@schukai/monster 3.85.1 → 3.86.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/package.json +1 -1
  3. package/source/components/content/copy.mjs +1 -3
  4. package/source/components/datatable/columnbar.mjs +15 -36
  5. package/source/components/datatable/datasource/dom.mjs +1 -0
  6. package/source/components/datatable/datatable/header.mjs +4 -2
  7. package/source/components/datatable/datatable.mjs +758 -765
  8. package/source/components/datatable/style/datatable.pcss +41 -9
  9. package/source/components/datatable/stylesheet/datatable.mjs +7 -14
  10. package/source/components/datatable/util.mjs +1 -0
  11. package/source/components/form/button-bar.mjs +3 -36
  12. package/source/components/form/button.mjs +0 -1
  13. package/source/components/form/style/button-bar.pcss +3 -2
  14. package/source/components/form/style/button.pcss +6 -1
  15. package/source/components/form/style/confirm-button.pcss +6 -1
  16. package/source/components/form/style/message-state-button.pcss +6 -2
  17. package/source/components/form/style/popper-button.pcss +7 -1
  18. package/source/components/form/style/select.pcss +2 -2
  19. package/source/components/form/style/state-button.pcss +4 -1
  20. package/source/components/form/stylesheet/button-bar.mjs +7 -14
  21. package/source/components/form/stylesheet/button.mjs +7 -14
  22. package/source/components/form/stylesheet/confirm-button.mjs +7 -14
  23. package/source/components/form/stylesheet/message-state-button.mjs +7 -14
  24. package/source/components/form/stylesheet/popper-button.mjs +7 -14
  25. package/source/components/form/stylesheet/select.mjs +7 -14
  26. package/source/components/form/stylesheet/state-button.mjs +7 -14
  27. package/source/components/layout/stylesheet/panel.mjs +7 -14
  28. package/source/dom/ready.mjs +1 -1
@@ -12,75 +12,75 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import { Datasource } from "./datasource.mjs";
15
+ import {Datasource} from "./datasource.mjs";
16
16
  import {
17
- assembleMethodSymbol,
18
- CustomElement,
19
- registerCustomElement,
20
- getSlottedElements,
17
+ assembleMethodSymbol,
18
+ CustomElement,
19
+ registerCustomElement,
20
+ getSlottedElements,
21
21
  } from "../../dom/customelement.mjs";
22
22
  import {
23
- findTargetElementFromEvent,
24
- fireCustomEvent,
23
+ findTargetElementFromEvent,
24
+ fireCustomEvent,
25
25
  } from "../../dom/events.mjs";
26
- import { clone } from "../../util/clone.mjs";
26
+ import {clone} from "../../util/clone.mjs";
27
27
  import {
28
- isString,
29
- isFunction,
30
- isInstance,
31
- isObject,
32
- isArray,
28
+ isString,
29
+ isFunction,
30
+ isInstance,
31
+ isObject,
32
+ isArray,
33
33
  } from "../../types/is.mjs";
34
34
  import {
35
- validateArray,
36
- validateInteger,
37
- validateObject,
35
+ validateArray,
36
+ validateInteger,
37
+ validateObject,
38
38
  } from "../../types/validate.mjs";
39
- import { Observer } from "../../types/observer.mjs";
39
+ import {Observer} from "../../types/observer.mjs";
40
40
  import {
41
- ATTRIBUTE_DATATABLE_HEAD,
42
- ATTRIBUTE_DATATABLE_GRID_TEMPLATE,
43
- ATTRIBUTE_DATASOURCE_SELECTOR,
44
- ATTRIBUTE_DATATABLE_ALIGN,
45
- ATTRIBUTE_DATATABLE_SORTABLE,
46
- ATTRIBUTE_DATATABLE_MODE,
47
- ATTRIBUTE_DATATABLE_INDEX,
48
- ATTRIBUTE_DATATABLE_MODE_HIDDEN,
49
- ATTRIBUTE_DATATABLE_MODE_VISIBLE,
50
- ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
51
- ATTRIBUTE_DATATABLE_MODE_FIXED,
41
+ ATTRIBUTE_DATATABLE_HEAD,
42
+ ATTRIBUTE_DATATABLE_GRID_TEMPLATE,
43
+ ATTRIBUTE_DATASOURCE_SELECTOR,
44
+ ATTRIBUTE_DATATABLE_ALIGN,
45
+ ATTRIBUTE_DATATABLE_SORTABLE,
46
+ ATTRIBUTE_DATATABLE_MODE,
47
+ ATTRIBUTE_DATATABLE_INDEX,
48
+ ATTRIBUTE_DATATABLE_MODE_HIDDEN,
49
+ ATTRIBUTE_DATATABLE_MODE_VISIBLE,
50
+ ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
51
+ ATTRIBUTE_DATATABLE_MODE_FIXED,
52
52
  } from "./constants.mjs";
53
- import { instanceSymbol } from "../../constants.mjs";
53
+ import {instanceSymbol} from "../../constants.mjs";
54
54
  import {
55
- Header,
56
- createOrderStatement,
57
- DIRECTION_ASC,
58
- DIRECTION_DESC,
59
- DIRECTION_NONE,
55
+ Header,
56
+ createOrderStatement,
57
+ DIRECTION_ASC,
58
+ DIRECTION_DESC,
59
+ DIRECTION_NONE,
60
60
  } from "./datatable/header.mjs";
61
- import { DatatableStyleSheet } from "./stylesheet/datatable.mjs";
61
+ import {DatatableStyleSheet} from "./stylesheet/datatable.mjs";
62
62
  import {
63
- handleDataSourceChanges,
64
- datasourceLinkedElementSymbol,
63
+ handleDataSourceChanges,
64
+ datasourceLinkedElementSymbol,
65
65
  } from "./util.mjs";
66
66
  import "./columnbar.mjs";
67
67
  import "./filter-button.mjs";
68
68
  import {
69
- findElementWithSelectorUpwards,
70
- getDocument,
71
- getWindow,
69
+ findElementWithSelectorUpwards,
70
+ getDocument,
71
+ getWindow,
72
72
  } from "../../dom/util.mjs";
73
- import { addAttributeToken } from "../../dom/attributes.mjs";
74
- import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs";
75
- import { getDocumentTranslations } from "../../i18n/translations.mjs";
73
+ import {addAttributeToken} from "../../dom/attributes.mjs";
74
+ import {ATTRIBUTE_ERRORMESSAGE} from "../../dom/constants.mjs";
75
+ import {getDocumentTranslations} from "../../i18n/translations.mjs";
76
76
  import "../state/state.mjs";
77
77
  import "../host/collapse.mjs";
78
- import { generateUniqueConfigKey } from "../host/util.mjs";
78
+ import {generateUniqueConfigKey} from "../host/util.mjs";
79
79
 
80
80
  import "./datasource/dom.mjs";
81
81
  import "./datasource/rest.mjs";
82
82
 
83
- export { DataTable };
83
+ export {DataTable};
84
84
 
85
85
  /**
86
86
  * @private
@@ -103,394 +103,387 @@ const columnBarElementSymbol = Symbol("columnBarElement");
103
103
  /**
104
104
  * The DataTable component is used to show the data from a data source.
105
105
  *
106
- * <img src="./images/datatable.png">
107
- *
108
- * Dependencies: the system uses functions of the [monsterjs](https://monsterjs.org/) library
109
- *
110
- * You can create this control either by specifying the HTML tag <monster-datatable />` directly in the HTML or using
111
- * Javascript via the `document.createElement('monster-datatable');` method.
112
- *
113
- * ```html
114
- * <monster-datatable></monster-datatable>
115
- * ```
116
- *
117
- * Or you can create this CustomControl directly in Javascript:
118
- *
119
- * ```js
120
- * import '@schukai/component-datatable/source/datatable.mjs';
121
- * document.createElement('monster-datatable');
122
- * ```
123
- *
124
- * The Body should have a class "hidden" to ensure that the styles are applied correctly.
106
+ * @copyright schukai GmbH
107
+ * @summary A data table
108
+
109
+ */
110
+
111
+ /**
112
+ * A DataTable
125
113
  *
126
- * ```css
127
- * body.hidden {
128
- * visibility: hidden;
129
- * }
130
- * ```
114
+ * @fragments /fragments/components/datatable/datatable/
131
115
  *
132
- * @startuml datatable.png
133
- * skinparam monochrome true
134
- * skinparam shadowing false
135
- * HTMLElement <|-- CustomElement
136
- * CustomElement <|-- DataTable
137
- * @enduml
116
+ * @example /examples/components/datatable/empty
117
+ * @example /examples/components/datatable/data-using-javascript
118
+ * @example /examples/components/datatable/alignment
119
+ * @example /examples/components/datatable/row-mode
120
+ * @example /examples/components/datatable/grid-template
121
+ * @example /examples/components/datatable/overview-class
138
122
  *
139
123
  * @copyright schukai GmbH
140
- * @summary A data table
124
+ * @summary A beautiful and highly customizable data table. It can be used to display data from a data source.
141
125
  * @fires monster-datatable-row-copied
142
126
  * @fires monster-datatable-row-removed
143
127
  * @fires monster-datatable-row-added
144
- */
128
+ **/
145
129
  class DataTable extends CustomElement {
146
- /**
147
- * This method is called by the `instanceof` operator.
148
- * @return {symbol}
149
- */
150
- static get [instanceSymbol]() {
151
- return Symbol.for("@schukai/monster/components/datatable@@instance");
152
- }
153
-
154
- /**
155
- * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
156
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
157
- *
158
- * The individual configuration values can be found in the table.
159
- *
160
- * @property {Object} templates Template definitions
161
- * @property {string} templates.main Main template
162
- * @property {Object} datasource Datasource configuration
163
- * @property {string} datasource.selector Selector for the datasource
164
- * @property {Object} mapping Mapping configuration
165
- * @property {string} mapping.data Data mapping
166
- * @property {Array} data Data
167
- * @property {Array} headers Headers
168
- * @property {Object} responsive Responsive configuration
169
- * @property {number} responsive.breakpoint Breakpoint for responsive mode
170
- * @property {Object} labels Labels
171
- * @property {string} labels.theListContainsNoEntries Label for empty state
172
- * @property {Object} classes Classes
173
- * @property {string} classes.container Container class
174
- * @property {Object} features Features
175
- * @property {boolean} features.settings Settings feature
176
- * @property {boolean} features.footer Footer feature
177
- * @property {boolean} features.autoInit Auto init feature (init datasource automatically)
178
- * @property {Object} templateMapping Template mapping
179
- * @property {string} templateMapping.row-key Row key
180
- * @property {string} templateMapping.filter-id Filter id
181
- **/
182
- get defaults() {
183
- return Object.assign(
184
- {},
185
- super.defaults,
186
- {
187
- templates: {
188
- main: getTemplate(),
189
- emptyState: getEmptyTemplate(),
190
- },
191
-
192
- datasource: {
193
- selector: null,
194
- },
195
-
196
- mapping: {
197
- data: "dataset",
198
- },
199
-
200
- data: [],
201
- headers: [],
202
-
203
- responsive: {
204
- breakpoint: 800,
205
- },
206
-
207
- labels: {
208
- theListContainsNoEntries: "The list contains no entries",
209
- },
210
-
211
- classes: {
212
- control: "monster-theme-control-container-1",
213
- container: "",
214
- row: "monster-theme-control-row-1",
215
- },
216
-
217
- features: {
218
- settings: true,
219
- footer: true,
220
- autoInit: true,
221
- },
222
-
223
- templateMapping: {
224
- "row-key": null,
225
- "filter-id": null,
226
- },
227
- },
228
- initOptionsFromArguments.call(this),
229
- );
230
- }
231
-
232
- /**
233
- *
234
- * @param {string} selector
235
- * @return {NodeListOf<*>}
236
- */
237
- getGridElements(selector) {
238
- return this[gridElementSymbol].querySelectorAll(selector);
239
- }
240
-
241
- /**
242
- *
243
- * @return {string}
244
- */
245
- static getTag() {
246
- return "monster-datatable";
247
- }
248
-
249
- /**
250
- *
251
- * @return {Monster.Components.Form.Form}
252
- */
253
- [assembleMethodSymbol]() {
254
- const rawKey = this.getOption("templateMapping.row-key");
255
-
256
- if (rawKey === null) {
257
- if (this.id !== null && this.id !== "") {
258
- const rawKey = this.getOption("templateMapping.row-key");
259
- if (rawKey === null) {
260
- this.setOption("templateMapping.row-key", this.id + "-row");
261
- }
262
- } else {
263
- this.setOption("templateMapping.row-key", "row");
264
- }
265
- }
266
-
267
- if (this.id !== null && this.id !== "") {
268
- this.setOption("templateMapping.filter-id", "" + this.id + "-filter");
269
- } else {
270
- this.setOption("templateMapping.filter-id", "filter");
271
- }
272
-
273
- super[assembleMethodSymbol]();
274
-
275
- initControlReferences.call(this);
276
- initEventHandler.call(this);
277
-
278
- const selector = this.getOption("datasource.selector");
279
-
280
- if (isString(selector)) {
281
- const element = findElementWithSelectorUpwards(this, selector);
282
- if (element === null) {
283
- throw new Error("the selector must match exactly one element");
284
- }
285
-
286
- if (!isInstance(element, Datasource)) {
287
- throw new TypeError("the element must be a datasource");
288
- }
289
-
290
- this[datasourceLinkedElementSymbol] = element;
291
-
292
- queueMicrotask(() => {
293
- handleDataSourceChanges.call(this);
294
- element.datasource.attachObserver(
295
- new Observer(handleDataSourceChanges.bind(this)),
296
- );
297
- });
298
- }
299
-
300
- getHostConfig
301
- .call(this, getColumnVisibilityConfigKey)
302
- .then((config) => {
303
- const headerOrderMap = new Map();
304
-
305
- getHostConfig
306
- .call(this, getStoredOrderConfigKey)
307
- .then((orderConfig) => {
308
- if (isArray(orderConfig) || orderConfig.length > 0) {
309
- for (let i = 0; i < orderConfig.length; i++) {
310
- const item = orderConfig[i];
311
- const parts = item.split(" ");
312
- const field = parts[0];
313
- const direction = parts[1] || DIRECTION_ASC;
314
- headerOrderMap.set(field, direction);
315
- }
316
- }
317
- })
318
- .then(() => {
319
- try {
320
- initGridAndStructs.call(this, config, headerOrderMap);
321
- } catch (error) {
322
- addAttributeToken(
323
- this,
324
- ATTRIBUTE_ERRORMESSAGE,
325
- error?.message || error.toString(),
326
- );
327
- }
328
-
329
- updateColumnBar.call(this);
330
- })
331
- .catch((error) => {
332
- addAttributeToken(
333
- this,
334
- ATTRIBUTE_ERRORMESSAGE,
335
- error?.message || error.toString(),
336
- );
337
- });
338
- })
339
- .catch((error) => {
340
- addAttributeToken(
341
- this,
342
- ATTRIBUTE_ERRORMESSAGE,
343
- error?.message || error.toString(),
344
- );
345
- });
346
- }
347
-
348
- /**
349
- *
350
- * @return {CSSStyleSheet[]}
351
- */
352
- static getCSSStyleSheet() {
353
- return [DatatableStyleSheet];
354
- }
355
-
356
- /**
357
- * Copy a row from the datatable
358
- * @param {number} fromIndex
359
- * @param {number} toIndex
360
- * @return {Monster.Components.Datatable.DataTable}
361
- * @fires monster-datatable-row-copied
362
- */
363
- copyRow(fromIndex, toIndex) {
364
- const datasource = this[datasourceLinkedElementSymbol];
365
- if (!datasource) {
366
- return this;
367
- }
368
- let d = datasource.data;
369
- let c = clone(d);
370
-
371
- let rows = c;
372
- const mapping = this.getOption("mapping.data");
373
-
374
- if (mapping) {
375
- rows = c?.[mapping];
376
- }
377
-
378
- if (rows === undefined || rows === null) {
379
- rows = [];
380
- }
381
-
382
- if (toIndex === undefined) {
383
- toIndex = rows.length;
384
- }
385
-
386
- fromIndex = parseInt(fromIndex);
387
- toIndex = parseInt(toIndex);
388
-
389
- if (toIndex < 0 || toIndex > rows.length) {
390
- throw new RangeError("index out of bounds");
391
- }
392
-
393
- validateArray(rows);
394
- validateInteger(fromIndex);
395
- validateInteger(toIndex);
396
-
397
- if (fromIndex < 0 || fromIndex >= rows.length) {
398
- throw new RangeError("index out of bounds");
399
- }
400
-
401
- rows.splice(toIndex, 0, clone(rows[fromIndex]));
402
- datasource.data = c;
403
-
404
- fireCustomEvent(this, "monster-datatable-row-copied", {
405
- index: toIndex,
406
- });
407
-
408
- return this;
409
- }
410
-
411
- /**
412
- * Remove a row from the datatable
413
- * @param index
414
- * @return {Monster.Components.Datatable.DataTable}
415
- * @fires monster-datatable-row-removed
416
- */
417
- removeRow(index) {
418
- const datasource = this[datasourceLinkedElementSymbol];
419
- if (!datasource) {
420
- return this;
421
- }
422
- let d = datasource.data;
423
- let c = clone(d);
424
-
425
- let rows = c;
426
- const mapping = this.getOption("mapping.data");
427
-
428
- if (mapping) {
429
- rows = c?.[mapping];
430
- }
431
-
432
- if (rows === undefined || rows === null) {
433
- rows = [];
434
- }
435
-
436
- index = parseInt(index);
437
-
438
- validateArray(rows);
439
- validateInteger(index);
440
- if (index < 0 || index >= rows.length) {
441
- throw new RangeError("index out of bounds");
442
- }
443
- if (mapping) {
444
- rows = c?.[mapping];
445
- }
446
-
447
- rows.splice(index, 1);
448
- datasource.data = c;
449
-
450
- fireCustomEvent(this, "monster-datatable-row-removed", {
451
- index: index,
452
- });
453
-
454
- return this;
455
- }
456
-
457
- /**
458
- * Add a row to the datatable
459
- * @param {Object} data
460
- * @return {Monster.Components.Datatable.DataTable}
461
- * @fires monster-datatable-row-added
462
- **/
463
- addRow(data) {
464
- const datasource = this[datasourceLinkedElementSymbol];
465
- if (!datasource) {
466
- return this;
467
- }
468
- let d = datasource.data;
469
- let c = clone(d);
470
-
471
- let rows = c;
472
-
473
- const mapping = this.getOption("mapping.data");
474
- if (mapping) {
475
- rows = c?.[mapping];
476
- }
477
-
478
- if (rows === undefined || rows === null) {
479
- rows = [];
480
- }
481
-
482
- validateArray(rows);
483
- validateObject(data);
484
-
485
- rows.push(data);
486
- datasource.data = c;
487
-
488
- fireCustomEvent(this, "monster-datatable-row-added", {
489
- index: rows.length - 1,
490
- });
491
-
492
- return this;
493
- }
130
+ /**
131
+ * This method is called by the `instanceof` operator.
132
+ * @return {symbol}
133
+ */
134
+ static get [instanceSymbol]() {
135
+ return Symbol.for("@schukai/monster/components/datatable@@instance");
136
+ }
137
+
138
+ /**
139
+ * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
140
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
141
+ *
142
+ * The individual configuration values can be found in the table.
143
+ *
144
+ * @property {Object} templates Template definitions
145
+ * @property {string} templates.main Main template
146
+ * @property {Object} datasource Datasource configuration
147
+ * @property {string} datasource.selector Selector for the datasource
148
+ * @property {Object} mapping Mapping configuration
149
+ * @property {string} mapping.data Data mapping
150
+ * @property {Array} data Data
151
+ * @property {Array} headers Headers
152
+ * @property {Object} responsive Responsive configuration
153
+ * @property {number} responsive.breakpoint Breakpoint for responsive mode
154
+ * @property {Object} labels Labels
155
+ * @property {string} labels.theListContainsNoEntries Label for empty state
156
+ * @property {Object} classes Classes
157
+ * @property {string} classes.container Container class
158
+ * @property {Object} features Features
159
+ * @property {boolean} features.settings Settings feature
160
+ * @property {boolean} features.footer Footer feature
161
+ * @property {boolean} features.autoInit Auto init feature (init datasource automatically)
162
+ * @property {Object} templateMapping Template mapping
163
+ * @property {string} templateMapping.row-key Row key
164
+ * @property {string} templateMapping.filter-id Filter id
165
+ **/
166
+ get defaults() {
167
+ return Object.assign(
168
+ {},
169
+ super.defaults,
170
+ {
171
+ templates: {
172
+ main: getTemplate(),
173
+ emptyState: getEmptyTemplate(),
174
+ },
175
+
176
+ datasource: {
177
+ selector: null,
178
+ },
179
+
180
+ mapping: {
181
+ data: "dataset",
182
+ },
183
+
184
+ data: [],
185
+ headers: [],
186
+
187
+ responsive: {
188
+ breakpoint: 800,
189
+ },
190
+
191
+ labels: {
192
+ theListContainsNoEntries: "The list contains no entries",
193
+ },
194
+
195
+ classes: {
196
+ control: "monster-theme-control-container-1",
197
+ container: "",
198
+ row: "monster-theme-control-row-1",
199
+ },
200
+
201
+ features: {
202
+ settings: true,
203
+ footer: true,
204
+ autoInit: true,
205
+ },
206
+
207
+ templateMapping: {
208
+ "row-key": null,
209
+ "filter-id": null,
210
+ },
211
+ },
212
+ initOptionsFromArguments.call(this),
213
+ );
214
+ }
215
+
216
+ /**
217
+ *
218
+ * @param {string} selector
219
+ * @return {NodeListOf<*>}
220
+ */
221
+ getGridElements(selector) {
222
+ return this[gridElementSymbol].querySelectorAll(selector);
223
+ }
224
+
225
+ /**
226
+ *
227
+ * @return {string}
228
+ */
229
+ static getTag() {
230
+ return "monster-datatable";
231
+ }
232
+
233
+ /**
234
+ * @return void
235
+ */
236
+ [assembleMethodSymbol]() {
237
+ const rawKey = this.getOption("templateMapping.row-key");
238
+
239
+ if (rawKey === null) {
240
+ if (this.id !== null && this.id !== "") {
241
+ const rawKey = this.getOption("templateMapping.row-key");
242
+ if (rawKey === null) {
243
+ this.setOption("templateMapping.row-key", this.id + "-row");
244
+ }
245
+ } else {
246
+ this.setOption("templateMapping.row-key", "row");
247
+ }
248
+ }
249
+
250
+ if (this.id !== null && this.id !== "") {
251
+ this.setOption("templateMapping.filter-id", "" + this.id + "-filter");
252
+ } else {
253
+ this.setOption("templateMapping.filter-id", "filter");
254
+ }
255
+
256
+ super[assembleMethodSymbol]();
257
+
258
+ initControlReferences.call(this);
259
+ initEventHandler.call(this);
260
+
261
+ const selector = this.getOption("datasource.selector");
262
+
263
+ if (isString(selector)) {
264
+ const element = findElementWithSelectorUpwards(this, selector);
265
+ if (element === null) {
266
+ throw new Error("the selector must match exactly one element");
267
+ }
268
+
269
+ if (!isInstance(element, Datasource)) {
270
+ throw new TypeError("the element must be a datasource");
271
+ }
272
+
273
+ this[datasourceLinkedElementSymbol] = element;
274
+
275
+ queueMicrotask(() => {
276
+ handleDataSourceChanges.call(this);
277
+ element.datasource.attachObserver(
278
+ new Observer(handleDataSourceChanges.bind(this)),
279
+ );
280
+ });
281
+ }
282
+
283
+ getHostConfig
284
+ .call(this, getColumnVisibilityConfigKey)
285
+ .then((config) => {
286
+ const headerOrderMap = new Map();
287
+
288
+ getHostConfig
289
+ .call(this, getStoredOrderConfigKey)
290
+ .then((orderConfig) => {
291
+ if (isArray(orderConfig) || orderConfig.length > 0) {
292
+ for (let i = 0; i < orderConfig.length; i++) {
293
+ const item = orderConfig[i];
294
+ const parts = item.split(" ");
295
+ const field = parts[0];
296
+ const direction = parts[1] || DIRECTION_ASC;
297
+ headerOrderMap.set(field, direction);
298
+ }
299
+ }
300
+ })
301
+ .then(() => {
302
+ try {
303
+ initGridAndStructs.call(this, config, headerOrderMap);
304
+ } catch (error) {
305
+ addAttributeToken(
306
+ this,
307
+ ATTRIBUTE_ERRORMESSAGE,
308
+ error?.message || error.toString(),
309
+ );
310
+ }
311
+
312
+ updateColumnBar.call(this);
313
+ })
314
+ .catch((error) => {
315
+ addAttributeToken(
316
+ this,
317
+ ATTRIBUTE_ERRORMESSAGE,
318
+ error?.message || error.toString(),
319
+ );
320
+ });
321
+ })
322
+ .catch((error) => {
323
+ addAttributeToken(
324
+ this,
325
+ ATTRIBUTE_ERRORMESSAGE,
326
+ error?.message || error.toString(),
327
+ );
328
+ });
329
+ }
330
+
331
+ /**
332
+ * @return {CSSStyleSheet[]}
333
+ */
334
+ static getCSSStyleSheet() {
335
+ return [DatatableStyleSheet];
336
+ }
337
+
338
+ /**
339
+ * Copy a row from the datatable
340
+ *
341
+ * @param {number|string} fromIndex
342
+ * @param {number|string} toIndex
343
+ * @return {DataTable}
344
+ * @fires monster-datatable-row-copied
345
+ */
346
+ copyRow(fromIndex, toIndex) {
347
+ const datasource = this[datasourceLinkedElementSymbol];
348
+ if (!datasource) {
349
+ return this;
350
+ }
351
+ let d = datasource.data;
352
+ let c = clone(d);
353
+
354
+ let rows = c;
355
+ const mapping = this.getOption("mapping.data");
356
+
357
+ if (mapping) {
358
+ rows = c?.[mapping];
359
+ }
360
+
361
+ if (rows === undefined || rows === null) {
362
+ rows = [];
363
+ }
364
+
365
+ if (toIndex === undefined) {
366
+ toIndex = rows.length;
367
+ }
368
+
369
+ if (isString(fromIndex)) {
370
+ fromIndex = parseInt(fromIndex);
371
+ }
372
+ if (isString(toIndex)) {
373
+ toIndex = parseInt(toIndex);
374
+ }
375
+
376
+ if (toIndex < 0 || toIndex > rows.length) {
377
+ throw new RangeError("index out of bounds");
378
+ }
379
+
380
+ validateArray(rows);
381
+ validateInteger(fromIndex);
382
+ validateInteger(toIndex);
383
+
384
+ if (fromIndex < 0 || fromIndex >= rows.length) {
385
+ throw new RangeError("index out of bounds");
386
+ }
387
+
388
+ rows.splice(toIndex, 0, clone(rows[fromIndex]));
389
+ datasource.data = c;
390
+
391
+ fireCustomEvent(this, "monster-datatable-row-copied", {
392
+ index: toIndex,
393
+ });
394
+
395
+ return this;
396
+ }
397
+
398
+ /**
399
+ * Remove a row from the datatable
400
+ *
401
+ * @param {number|string} index
402
+ * @return {DataTable}
403
+ * @fires monster-datatable-row-removed
404
+ */
405
+ removeRow(index) {
406
+ const datasource = this[datasourceLinkedElementSymbol];
407
+ if (!datasource) {
408
+ return this;
409
+ }
410
+ let d = datasource.data;
411
+ let c = clone(d);
412
+
413
+ let rows = c;
414
+ const mapping = this.getOption("mapping.data");
415
+
416
+ if (mapping) {
417
+ rows = c?.[mapping];
418
+ }
419
+
420
+ if (rows === undefined || rows === null) {
421
+ rows = [];
422
+ }
423
+
424
+ if (isString(index)) {
425
+ index = parseInt(index);
426
+ }
427
+
428
+ validateArray(rows);
429
+ validateInteger(index);
430
+
431
+ if (index < 0 || index >= rows.length) {
432
+ throw new RangeError("index out of bounds");
433
+ }
434
+ if (mapping) {
435
+ rows = c?.[mapping];
436
+ }
437
+
438
+ rows.splice(index, 1);
439
+ datasource.data = c;
440
+
441
+ fireCustomEvent(this, "monster-datatable-row-removed", {
442
+ index: index,
443
+ });
444
+
445
+ return this;
446
+ }
447
+
448
+ /**
449
+ * Add a row to the datatable
450
+ *
451
+ * @param {Object} data
452
+ * @return {DataTable}
453
+ *
454
+ * @fires monster-datatable-row-added
455
+ **/
456
+ addRow(data) {
457
+ const datasource = this[datasourceLinkedElementSymbol];
458
+ if (!datasource) {
459
+ return this;
460
+ }
461
+ let d = datasource.data;
462
+ let c = clone(d);
463
+
464
+ let rows = c;
465
+
466
+ const mapping = this.getOption("mapping.data");
467
+ if (mapping) {
468
+ rows = c?.[mapping];
469
+ }
470
+
471
+ if (rows === undefined || rows === null) {
472
+ rows = [];
473
+ }
474
+
475
+ validateArray(rows);
476
+ validateObject(data);
477
+
478
+ rows.push(data);
479
+ datasource.data = c;
480
+
481
+ fireCustomEvent(this, "monster-datatable-row-added", {
482
+ index: rows.length - 1,
483
+ });
484
+
485
+ return this;
486
+ }
494
487
  }
495
488
 
496
489
  /**
@@ -498,7 +491,7 @@ class DataTable extends CustomElement {
498
491
  * @return {string}
499
492
  */
500
493
  function getColumnVisibilityConfigKey() {
501
- return generateUniqueConfigKey("datatable", this?.id, "columns-visibility");
494
+ return generateUniqueConfigKey("datatable", this?.id, "columns-visibility");
502
495
  }
503
496
 
504
497
  /**
@@ -506,7 +499,7 @@ function getColumnVisibilityConfigKey() {
506
499
  * @return {string}
507
500
  */
508
501
  function getFilterConfigKey() {
509
- return generateUniqueConfigKey("datatable", this?.id, "filter");
502
+ return generateUniqueConfigKey("datatable", this?.id, "filter");
510
503
  }
511
504
 
512
505
  /**
@@ -514,291 +507,291 @@ function getFilterConfigKey() {
514
507
  * @return {Promise}
515
508
  */
516
509
  function getHostConfig(callback) {
517
- const host = findElementWithSelectorUpwards(this, "monster-host");
518
-
519
- if (!(host && this.id)) {
520
- return Promise.resolve({});
521
- }
522
-
523
- if (!host || !isFunction(host?.getConfig)) {
524
- throw new TypeError("the host must be a monster-host");
525
- }
526
-
527
- const configKey = callback.call(this);
528
- return host.hasConfig(configKey).then((hasConfig) => {
529
- if (hasConfig) {
530
- return host.getConfig(configKey);
531
- } else {
532
- return {};
533
- }
534
- });
510
+ const host = findElementWithSelectorUpwards(this, "monster-host");
511
+
512
+ if (!(host && this.id)) {
513
+ return Promise.resolve({});
514
+ }
515
+
516
+ if (!host || !isFunction(host?.getConfig)) {
517
+ throw new TypeError("the host must be a monster-host");
518
+ }
519
+
520
+ const configKey = callback.call(this);
521
+ return host.hasConfig(configKey).then((hasConfig) => {
522
+ if (hasConfig) {
523
+ return host.getConfig(configKey);
524
+ } else {
525
+ return {};
526
+ }
527
+ });
535
528
  }
536
529
 
537
530
  /**
538
531
  * @private
539
532
  */
540
533
  function updateColumnBar() {
541
- if (!this[columnBarElementSymbol]) {
542
- return;
543
- }
544
-
545
- const columns = [];
546
- for (const header of this.getOption("headers")) {
547
- const mode = header.getInternal("mode");
548
-
549
- if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
550
- continue;
551
- }
552
-
553
- columns.push({
554
- visible: mode !== ATTRIBUTE_DATATABLE_MODE_HIDDEN,
555
- name: header.label,
556
- index: header.index,
557
- });
558
- }
559
-
560
- this[columnBarElementSymbol].setOption("columns", columns);
534
+ if (!this[columnBarElementSymbol]) {
535
+ return;
536
+ }
537
+
538
+ const columns = [];
539
+ for (const header of this.getOption("headers")) {
540
+ const mode = header.getInternal("mode");
541
+
542
+ if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
543
+ continue;
544
+ }
545
+
546
+ columns.push({
547
+ visible: mode !== ATTRIBUTE_DATATABLE_MODE_HIDDEN,
548
+ name: header.label,
549
+ index: header.index,
550
+ });
551
+ }
552
+
553
+ this[columnBarElementSymbol].setOption("columns", columns);
561
554
  }
562
555
 
563
556
  /**
564
557
  * @private
565
558
  */
566
559
  function updateHeaderFromColumnBar() {
567
- if (!this[columnBarElementSymbol]) {
568
- return;
569
- }
560
+ if (!this[columnBarElementSymbol]) {
561
+ return;
562
+ }
570
563
 
571
- const options = this[columnBarElementSymbol].getOption("columns");
572
- if (!isArray(options)) return;
564
+ const options = this[columnBarElementSymbol].getOption("columns");
565
+ if (!isArray(options)) return;
573
566
 
574
- const invisibleMap = {};
567
+ const invisibleMap = {};
575
568
 
576
- for (let i = 0; i < options.length; i++) {
577
- const option = options[i];
578
- invisibleMap[option.index] = option.visible;
579
- }
569
+ for (let i = 0; i < options.length; i++) {
570
+ const option = options[i];
571
+ invisibleMap[option.index] = option.visible;
572
+ }
580
573
 
581
- for (const header of this.getOption("headers")) {
582
- const mode = header.getInternal("mode");
574
+ for (const header of this.getOption("headers")) {
575
+ const mode = header.getInternal("mode");
583
576
 
584
- if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
585
- continue;
586
- }
577
+ if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
578
+ continue;
579
+ }
587
580
 
588
- if (invisibleMap[header.index] === false) {
589
- header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_HIDDEN);
590
- } else {
591
- header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_VISIBLE);
592
- }
593
- }
581
+ if (invisibleMap[header.index] === false) {
582
+ header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_HIDDEN);
583
+ } else {
584
+ header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_VISIBLE);
585
+ }
586
+ }
594
587
  }
595
588
 
596
589
  /**
597
590
  * @private
598
591
  */
599
592
  function updateConfigColumnBar() {
600
- if (!this[columnBarElementSymbol]) {
601
- return;
602
- }
603
-
604
- const options = this[columnBarElementSymbol].getOption("columns");
605
- if (!isArray(options)) return;
606
-
607
- const map = {};
608
- for (let i = 0; i < options.length; i++) {
609
- const option = options[i];
610
- map[option.name] = option.visible;
611
- }
612
-
613
- const host = findElementWithSelectorUpwards(this, "monster-host");
614
- if (!(host && this.id)) {
615
- return;
616
- }
617
- const configKey = getColumnVisibilityConfigKey.call(this);
618
-
619
- try {
620
- host.setConfig(configKey, map);
621
- } catch (error) {
622
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
623
- }
593
+ if (!this[columnBarElementSymbol]) {
594
+ return;
595
+ }
596
+
597
+ const options = this[columnBarElementSymbol].getOption("columns");
598
+ if (!isArray(options)) return;
599
+
600
+ const map = {};
601
+ for (let i = 0; i < options.length; i++) {
602
+ const option = options[i];
603
+ map[option.name] = option.visible;
604
+ }
605
+
606
+ const host = findElementWithSelectorUpwards(this, "monster-host");
607
+ if (!(host && this.id)) {
608
+ return;
609
+ }
610
+ const configKey = getColumnVisibilityConfigKey.call(this);
611
+
612
+ try {
613
+ host.setConfig(configKey, map);
614
+ } catch (error) {
615
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
616
+ }
624
617
  }
625
618
 
626
619
  /**
627
620
  * @private
628
621
  */
629
622
  function initEventHandler() {
630
- const self = this;
631
-
632
- getWindow().addEventListener("resize", (event) => {
633
- updateGrid.call(self);
634
- });
635
-
636
- self[columnBarElementSymbol].attachObserver(
637
- new Observer((e) => {
638
- updateHeaderFromColumnBar.call(self);
639
- updateGrid.call(self);
640
- updateConfigColumnBar.call(self);
641
- }),
642
- );
643
-
644
- self[gridHeadersElementSymbol].addEventListener("click", function (event) {
645
- let element = null;
646
- const datasource = self[datasourceLinkedElementSymbol];
647
- if (!datasource) {
648
- return;
649
- }
650
-
651
- element = findTargetElementFromEvent(event, ATTRIBUTE_DATATABLE_SORTABLE);
652
- if (element) {
653
- const index = element.parentNode.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
654
- const headers = self.getOption("headers");
655
-
656
- event.preventDefault();
657
-
658
- headers[index].changeDirection();
659
-
660
- queueMicrotask(function () {
661
- /** hotfix, normally this should be done via the updater, no idea why this is not possible. */
662
- element.setAttribute(
663
- ATTRIBUTE_DATATABLE_SORTABLE,
664
- `${headers[index].field} ${headers[index].direction}`,
665
- );
666
-
667
- storeOrderStatement.call(self, true);
668
- });
669
- }
670
- });
623
+ const self = this;
624
+
625
+ getWindow().addEventListener("resize", (event) => {
626
+ updateGrid.call(self);
627
+ });
628
+
629
+ self[columnBarElementSymbol].attachObserver(
630
+ new Observer((e) => {
631
+ updateHeaderFromColumnBar.call(self);
632
+ updateGrid.call(self);
633
+ updateConfigColumnBar.call(self);
634
+ }),
635
+ );
636
+
637
+ self[gridHeadersElementSymbol].addEventListener("click", function (event) {
638
+ let element = null;
639
+ const datasource = self[datasourceLinkedElementSymbol];
640
+ if (!datasource) {
641
+ return;
642
+ }
643
+
644
+ element = findTargetElementFromEvent(event, ATTRIBUTE_DATATABLE_SORTABLE);
645
+ if (element) {
646
+ const index = element.parentNode.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
647
+ const headers = self.getOption("headers");
648
+
649
+ event.preventDefault();
650
+
651
+ headers[index].changeDirection();
652
+
653
+ queueMicrotask(function () {
654
+ /** hotfix, normally this should be done via the updater, no idea why this is not possible. */
655
+ element.setAttribute(
656
+ ATTRIBUTE_DATATABLE_SORTABLE,
657
+ `${headers[index].field} ${headers[index].direction}`,
658
+ );
659
+
660
+ storeOrderStatement.call(self, true);
661
+ });
662
+ }
663
+ });
671
664
  }
672
665
 
673
666
  /**
674
667
  * @private
675
668
  */
676
669
  function initGridAndStructs(hostConfig, headerOrderMap) {
677
- const rowID = this.getOption("templateMapping.row-key");
678
-
679
- if (!this[gridElementSymbol]) {
680
- throw new Error("no grid element is defined");
681
- }
682
-
683
- let template;
684
- getSlottedElements.call(this).forEach((e) => {
685
- if (e instanceof HTMLTemplateElement && e.id === rowID) {
686
- template = e;
687
- }
688
- });
689
-
690
- if (!template) {
691
- throw new Error("no template is defined");
692
- }
693
-
694
- const rowCount = template.content.children.length;
695
-
696
- const headers = [];
697
-
698
- for (let i = 0; i < rowCount; i++) {
699
- let hClass = "";
700
- const row = template.content.children[i];
701
-
702
- let mode = "";
703
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_MODE)) {
704
- mode = row.getAttribute(ATTRIBUTE_DATATABLE_MODE);
705
- }
706
-
707
- let grid = row.getAttribute(ATTRIBUTE_DATATABLE_GRID_TEMPLATE);
708
- if (!grid || grid === "" || grid === "auto") {
709
- grid = "minmax(0, 1fr)";
710
- }
711
-
712
- let label = "";
713
- let labelKey = "";
714
-
715
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_HEAD)) {
716
- label = row.getAttribute(ATTRIBUTE_DATATABLE_HEAD);
717
- labelKey = label;
718
-
719
- try {
720
- if (label.startsWith("i18n:")) {
721
- label = label.substring(5, label.length);
722
- label = getDocumentTranslations().getText(label, label);
723
- }
724
- } catch (e) {
725
- label = "i18n error " + label;
726
- }
727
- }
728
-
729
- if (!label) {
730
- label = i + 1 + "";
731
- mode = ATTRIBUTE_DATATABLE_MODE_FIXED;
732
- labelKey = label;
733
- }
734
-
735
- if (isObject(hostConfig) && hostConfig.hasOwnProperty(label)) {
736
- if (hostConfig[label] === false) {
737
- mode = ATTRIBUTE_DATATABLE_MODE_HIDDEN;
738
- } else {
739
- mode = ATTRIBUTE_DATATABLE_MODE_VISIBLE;
740
- }
741
- }
742
-
743
- let align = "";
744
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_ALIGN)) {
745
- align = row.getAttribute(ATTRIBUTE_DATATABLE_ALIGN);
746
- }
747
-
748
- switch (align) {
749
- case "center":
750
- hClass = "flex-center";
751
- break;
752
- case "end":
753
- hClass = "flex-end";
754
- break;
755
- case "start":
756
- hClass = "flex-start";
757
- break;
758
- default:
759
- hClass = "flex-start";
760
- }
761
-
762
- let field = "";
763
- let direction = DIRECTION_NONE;
764
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_SORTABLE)) {
765
- field = row.getAttribute(ATTRIBUTE_DATATABLE_SORTABLE).trim();
766
- const parts = field.split(" ").map((item) => item.trim());
767
- field = parts[0];
768
-
769
- if (headerOrderMap.has(field)) {
770
- direction = headerOrderMap.get(field);
771
- } else if (
772
- parts.length === 2 &&
773
- [DIRECTION_ASC, DIRECTION_DESC].indexOf(parts[1]) !== -1
774
- ) {
775
- direction = parts[1];
776
- }
777
- }
778
-
779
- if (mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
780
- hClass += " hidden";
781
- }
782
-
783
- const header = new Header();
784
- header.setInternals({
785
- field: field,
786
- label: label,
787
- classes: hClass,
788
- index: i,
789
- mode: mode,
790
- grid: grid,
791
- labelKey: labelKey,
792
- direction: direction,
793
- });
794
-
795
- headers.push(header);
796
- }
797
-
798
- this.setOption("headers", headers);
799
- queueMicrotask(() => {
800
- storeOrderStatement.call(this, this.getOption("features.autoInit"));
801
- });
670
+ const rowID = this.getOption("templateMapping.row-key");
671
+
672
+ if (!this[gridElementSymbol]) {
673
+ throw new Error("no grid element is defined");
674
+ }
675
+
676
+ let template;
677
+ getSlottedElements.call(this).forEach((e) => {
678
+ if (e instanceof HTMLTemplateElement && e.id === rowID) {
679
+ template = e;
680
+ }
681
+ });
682
+
683
+ if (!template) {
684
+ throw new Error("no template is defined");
685
+ }
686
+
687
+ const rowCount = template.content.children.length;
688
+
689
+ const headers = [];
690
+
691
+ for (let i = 0; i < rowCount; i++) {
692
+ let hClass = "";
693
+ const row = template.content.children[i];
694
+
695
+ let mode = "";
696
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_MODE)) {
697
+ mode = row.getAttribute(ATTRIBUTE_DATATABLE_MODE);
698
+ }
699
+
700
+ let grid = row.getAttribute(ATTRIBUTE_DATATABLE_GRID_TEMPLATE);
701
+ if (!grid || grid === "" || grid === "auto") {
702
+ grid = "minmax(0, 1fr)";
703
+ }
704
+
705
+ let label = "";
706
+ let labelKey = "";
707
+
708
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_HEAD)) {
709
+ label = row.getAttribute(ATTRIBUTE_DATATABLE_HEAD);
710
+ labelKey = label;
711
+
712
+ try {
713
+ if (label.startsWith("i18n:")) {
714
+ label = label.substring(5, label.length);
715
+ label = getDocumentTranslations().getText(label, label);
716
+ }
717
+ } catch (e) {
718
+ label = "i18n error " + label;
719
+ }
720
+ }
721
+
722
+ if (!label) {
723
+ label = i + 1 + "";
724
+ mode = ATTRIBUTE_DATATABLE_MODE_FIXED;
725
+ labelKey = label;
726
+ }
727
+
728
+ if (isObject(hostConfig) && hostConfig.hasOwnProperty(label)) {
729
+ if (hostConfig[label] === false) {
730
+ mode = ATTRIBUTE_DATATABLE_MODE_HIDDEN;
731
+ } else {
732
+ mode = ATTRIBUTE_DATATABLE_MODE_VISIBLE;
733
+ }
734
+ }
735
+
736
+ let align = "";
737
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_ALIGN)) {
738
+ align = row.getAttribute(ATTRIBUTE_DATATABLE_ALIGN);
739
+ }
740
+
741
+ switch (align) {
742
+ case "center":
743
+ hClass = "flex-center";
744
+ break;
745
+ case "end":
746
+ hClass = "flex-end";
747
+ break;
748
+ case "start":
749
+ hClass = "flex-start";
750
+ break;
751
+ default:
752
+ hClass = "flex-start";
753
+ }
754
+
755
+ let field = "";
756
+ let direction = DIRECTION_NONE;
757
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_SORTABLE)) {
758
+ field = row.getAttribute(ATTRIBUTE_DATATABLE_SORTABLE).trim();
759
+ const parts = field.split(" ").map((item) => item.trim());
760
+ field = parts[0];
761
+
762
+ if (headerOrderMap.has(field)) {
763
+ direction = headerOrderMap.get(field);
764
+ } else if (
765
+ parts.length === 2 &&
766
+ [DIRECTION_ASC, DIRECTION_DESC].indexOf(parts[1]) !== -1
767
+ ) {
768
+ direction = parts[1];
769
+ }
770
+ }
771
+
772
+ if (mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
773
+ hClass += " hidden";
774
+ }
775
+
776
+ const header = new Header();
777
+ header.setInternals({
778
+ field: field,
779
+ label: label,
780
+ classes: hClass,
781
+ index: i,
782
+ mode: mode,
783
+ grid: grid,
784
+ labelKey: labelKey,
785
+ direction: direction,
786
+ });
787
+
788
+ headers.push(header);
789
+ }
790
+
791
+ this.setOption("headers", headers);
792
+ queueMicrotask(() => {
793
+ storeOrderStatement.call(this, this.getOption("features.autoInit"));
794
+ });
802
795
  }
803
796
 
804
797
  /**
@@ -806,75 +799,75 @@ function initGridAndStructs(hostConfig, headerOrderMap) {
806
799
  * @return {string}
807
800
  */
808
801
  export function getStoredOrderConfigKey() {
809
- return generateUniqueConfigKey("datatable", this?.id, "stored-order");
802
+ return generateUniqueConfigKey("datatable", this?.id, "stored-order");
810
803
  }
811
804
 
812
805
  /**
813
806
  * @private
814
807
  */
815
808
  function storeOrderStatement(doFetch) {
816
- const headers = this.getOption("headers");
817
- const statement = createOrderStatement(headers);
818
- setDataSource.call(this, { orderBy: statement }, doFetch);
809
+ const headers = this.getOption("headers");
810
+ const statement = createOrderStatement(headers);
811
+ setDataSource.call(this, {orderBy: statement}, doFetch);
819
812
 
820
- const host = findElementWithSelectorUpwards(this, "monster-host");
821
- if (!(host && this.id)) {
822
- return;
823
- }
813
+ const host = findElementWithSelectorUpwards(this, "monster-host");
814
+ if (!(host && this.id)) {
815
+ return;
816
+ }
824
817
 
825
- const configKey = getStoredOrderConfigKey.call(this);
818
+ const configKey = getStoredOrderConfigKey.call(this);
826
819
 
827
- // statement explode with , and remove all empty
828
- const list = statement.split(",").filter((item) => item.trim() !== "");
829
- if (list.length === 0) {
830
- return;
831
- }
820
+ // statement explode with , and remove all empty
821
+ const list = statement.split(",").filter((item) => item.trim() !== "");
822
+ if (list.length === 0) {
823
+ return;
824
+ }
832
825
 
833
- host.setConfig(configKey, list);
826
+ host.setConfig(configKey, list);
834
827
  }
835
828
 
836
829
  /**
837
830
  * @private
838
831
  */
839
832
  function updateGrid() {
840
- if (!this[gridElementSymbol]) {
841
- throw new Error("no grid element is defined");
842
- }
833
+ if (!this[gridElementSymbol]) {
834
+ throw new Error("no grid element is defined");
835
+ }
843
836
 
844
- let gridTemplateColumns = "";
837
+ let gridTemplateColumns = "";
845
838
 
846
- const headers = this.getOption("headers");
839
+ const headers = this.getOption("headers");
847
840
 
848
- let styles = "";
841
+ let styles = "";
849
842
 
850
- for (let i = 0; i < headers.length; i++) {
851
- const header = headers[i];
843
+ for (let i = 0; i < headers.length; i++) {
844
+ const header = headers[i];
852
845
 
853
- if (header.mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
854
- styles += `[data-monster-role=datatable]>[data-monster-head="${header.labelKey}"] { display: none; }\n`;
855
- styles += `[data-monster-role=datatable-headers]>[data-monster-index="${header.index}"] { display: none; }\n`;
856
- } else {
857
- gridTemplateColumns += `${header.grid} `;
858
- }
859
- }
846
+ if (header.mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
847
+ styles += `[data-monster-role=datatable]>[data-monster-head="${header.labelKey}"] { display: none; }\n`;
848
+ styles += `[data-monster-role=datatable-headers]>[data-monster-index="${header.index}"] { display: none; }\n`;
849
+ } else {
850
+ gridTemplateColumns += `${header.grid} `;
851
+ }
852
+ }
860
853
 
861
- const sheet = new CSSStyleSheet();
862
- if (styles !== "") sheet.replaceSync(styles);
863
- this.shadowRoot.adoptedStyleSheets = [...DataTable.getCSSStyleSheet(), sheet];
854
+ const sheet = new CSSStyleSheet();
855
+ if (styles !== "") sheet.replaceSync(styles);
856
+ this.shadowRoot.adoptedStyleSheets = [...DataTable.getCSSStyleSheet(), sheet];
864
857
 
865
- const bodyWidth = getDocument().body.getBoundingClientRect().width;
858
+ const bodyWidth = getDocument().body.getBoundingClientRect().width;
866
859
 
867
- const breakpoint = this.getOption("responsive.breakpoint");
860
+ const breakpoint = this.getOption("responsive.breakpoint");
868
861
 
869
- if (bodyWidth > breakpoint) {
870
- this[gridElementSymbol].style.gridTemplateColumns =
871
- `${gridTemplateColumns}`;
872
- this[gridHeadersElementSymbol].style.gridTemplateColumns =
873
- `${gridTemplateColumns}`;
874
- } else {
875
- this[gridElementSymbol].style.gridTemplateColumns = "auto";
876
- this[gridHeadersElementSymbol].style.gridTemplateColumns = "auto";
877
- }
862
+ if (bodyWidth > breakpoint) {
863
+ this[gridElementSymbol].style.gridTemplateColumns =
864
+ `${gridTemplateColumns}`;
865
+ this[gridHeadersElementSymbol].style.gridTemplateColumns =
866
+ `${gridTemplateColumns}`;
867
+ } else {
868
+ this[gridElementSymbol].style.gridTemplateColumns = "auto";
869
+ this[gridHeadersElementSymbol].style.gridTemplateColumns = "auto";
870
+ }
878
871
  }
879
872
 
880
873
  /**
@@ -882,20 +875,20 @@ function updateGrid() {
882
875
  * @param {Monster.Components.Datatable.Header[]} headers
883
876
  * @param {bool} doFetch
884
877
  */
885
- function setDataSource({ orderBy }, doFetch) {
886
- const datasource = this[datasourceLinkedElementSymbol];
878
+ function setDataSource({orderBy}, doFetch) {
879
+ const datasource = this[datasourceLinkedElementSymbol];
887
880
 
888
- if (!datasource) {
889
- return;
890
- }
881
+ if (!datasource) {
882
+ return;
883
+ }
891
884
 
892
- if (isFunction(datasource?.setParameters)) {
893
- datasource.setParameters({ orderBy });
894
- }
885
+ if (isFunction(datasource?.setParameters)) {
886
+ datasource.setParameters({orderBy});
887
+ }
895
888
 
896
- if (doFetch !== false && isFunction(datasource?.fetch)) {
897
- datasource.fetch();
898
- }
889
+ if (doFetch !== false && isFunction(datasource?.fetch)) {
890
+ datasource.fetch();
891
+ }
899
892
  }
900
893
 
901
894
  /**
@@ -903,20 +896,20 @@ function setDataSource({ orderBy }, doFetch) {
903
896
  * @return {Monster.Components.Datatable.Form}
904
897
  */
905
898
  function initControlReferences() {
906
- if (!this.shadowRoot) {
907
- throw new Error("no shadow-root is defined");
908
- }
909
-
910
- this[gridElementSymbol] = this.shadowRoot.querySelector(
911
- "[data-monster-role=datatable]",
912
- );
913
- this[gridHeadersElementSymbol] = this.shadowRoot.querySelector(
914
- "[data-monster-role=datatable-headers]",
915
- );
916
- this[columnBarElementSymbol] =
917
- this.shadowRoot.querySelector("monster-column-bar");
918
-
919
- return this;
899
+ if (!this.shadowRoot) {
900
+ throw new Error("no shadow-root is defined");
901
+ }
902
+
903
+ this[gridElementSymbol] = this.shadowRoot.querySelector(
904
+ "[data-monster-role=datatable]",
905
+ );
906
+ this[gridHeadersElementSymbol] = this.shadowRoot.querySelector(
907
+ "[data-monster-role=datatable-headers]",
908
+ );
909
+ this[columnBarElementSymbol] =
910
+ this.shadowRoot.querySelector("monster-column-bar");
911
+
912
+ return this;
920
913
  }
921
914
 
922
915
  /**
@@ -926,22 +919,22 @@ function initControlReferences() {
926
919
  * @throws {Error} the datasource could not be initialized
927
920
  */
928
921
  function initOptionsFromArguments() {
929
- const options = {};
930
- const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
931
-
932
- if (selector) {
933
- options.datasource = { selector: selector };
934
- }
935
-
936
- const breakpoint = this.getAttribute(
937
- ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
938
- );
939
- if (breakpoint) {
940
- options.responsive = {};
941
- options.responsive.breakpoint = parseInt(breakpoint);
942
- }
943
-
944
- return options;
922
+ const options = {};
923
+ const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
924
+
925
+ if (selector) {
926
+ options.datasource = {selector: selector};
927
+ }
928
+
929
+ const breakpoint = this.getAttribute(
930
+ ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
931
+ );
932
+ if (breakpoint) {
933
+ options.responsive = {};
934
+ options.responsive.breakpoint = parseInt(breakpoint);
935
+ }
936
+
937
+ return options;
945
938
  }
946
939
 
947
940
  /**
@@ -949,7 +942,7 @@ function initOptionsFromArguments() {
949
942
  * @return {string}
950
943
  */
951
944
  function getEmptyTemplate() {
952
- return `<monster-state data-monster-role="empty-without-action">
945
+ return `<monster-state data-monster-role="empty-without-action">
953
946
  <div part="visual">
954
947
  <svg width="4rem" height="4rem" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
955
948
  <path d="m21.5 22h-19c-1.378 0-2.5-1.121-2.5-2.5v-7c0-.07.015-.141.044-.205l3.969-8.82c.404-.896 1.299-1.475 2.28-1.475h11.414c.981 0 1.876.579 2.28 1.475l3.969 8.82c.029.064.044.135.044.205v7c0 1.379-1.122 2.5-2.5 2.5zm-20.5-9.393v6.893c0 .827.673 1.5 1.5 1.5h19c.827 0 1.5-.673 1.5-1.5v-6.893l-3.925-8.723c-.242-.536-.779-.884-1.368-.884h-11.414c-.589 0-1.126.348-1.368.885z"/>
@@ -967,8 +960,8 @@ function getEmptyTemplate() {
967
960
  * @return {string}
968
961
  */
969
962
  function getTemplate() {
970
- // language=HTML
971
- return `
963
+ // language=HTML
964
+ return `
972
965
  <div data-monster-role="control" part="control" data-monster-attributes="class path:classes.control">
973
966
  <template id="headers-row">
974
967
  <div data-monster-attributes="class path:headers-row.classes,
@@ -977,7 +970,7 @@ function getTemplate() {
977
970
  </template>
978
971
  <slot></slot>
979
972
  <div data-monster-attributes="class path:classes.container"
980
- data-monster-role="table-container" part="table-container">
973
+ data-monster-role="table-container" part="table-container">
981
974
  <div class="filter">
982
975
  <slot name="filter"></slot>
983
976
  </div>