@schukai/monster 3.97.1 → 3.98.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 (30) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +1 -1
  3. package/source/components/accessibility/locale-picker.mjs +549 -543
  4. package/source/components/datatable/columnbar.mjs +50 -3
  5. package/source/components/datatable/constants.mjs +7 -0
  6. package/source/components/datatable/datatable/header.mjs +1 -0
  7. package/source/components/datatable/datatable.mjs +1168 -934
  8. package/source/components/datatable/filter/date-range.mjs +145 -14
  9. package/source/components/datatable/filter/input.mjs +50 -3
  10. package/source/components/datatable/filter/range.mjs +92 -7
  11. package/source/components/datatable/filter-button.mjs +46 -3
  12. package/source/components/datatable/filter.mjs +95 -10
  13. package/source/components/datatable/pagination.mjs +82 -7
  14. package/source/components/datatable/save-button.mjs +46 -3
  15. package/source/components/datatable/style/datatable.pcss +1 -0
  16. package/source/components/datatable/stylesheet/datatable.mjs +7 -14
  17. package/source/components/form/field-set.mjs +77 -6
  18. package/source/components/form/select.mjs +149 -30
  19. package/source/components/layout/details.mjs +50 -3
  20. package/source/components/layout/tabs.mjs +50 -3
  21. package/source/components/notify/monitor-attribute-errors.mjs +235 -0
  22. package/source/components/notify/style/monitor-attribute-errors.pcss +0 -0
  23. package/source/components/notify/stylesheet/monitor-attribute-errors.mjs +38 -0
  24. package/source/dom/customelement.mjs +3 -3
  25. package/source/i18n/util.mjs +122 -122
  26. package/source/types/version.mjs +1 -1
  27. package/test/cases/monster.mjs +1 -1
  28. package/test/web/import.js +1 -0
  29. package/test/web/test.html +2 -2
  30. package/test/web/tests.js +432 -13
@@ -12,77 +12,80 @@
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_FEATURES,
50
+ ATTRIBUTE_DATATABLE_MODE_VISIBLE,
51
+ ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
52
+ ATTRIBUTE_DATATABLE_MODE_FIXED,
52
53
  } from "./constants.mjs";
53
- import { instanceSymbol } from "../../constants.mjs";
54
+ import {instanceSymbol} from "../../constants.mjs";
54
55
  import {
55
- Header,
56
- createOrderStatement,
57
- DIRECTION_ASC,
58
- DIRECTION_DESC,
59
- DIRECTION_NONE,
56
+ Header,
57
+ createOrderStatement,
58
+ DIRECTION_ASC,
59
+ DIRECTION_DESC,
60
+ DIRECTION_NONE,
60
61
  } from "./datatable/header.mjs";
61
- import { DatatableStyleSheet } from "./stylesheet/datatable.mjs";
62
+ import {DatatableStyleSheet} from "./stylesheet/datatable.mjs";
62
63
  import {
63
- handleDataSourceChanges,
64
- datasourceLinkedElementSymbol,
64
+ handleDataSourceChanges,
65
+ datasourceLinkedElementSymbol,
65
66
  } from "./util.mjs";
66
67
  import "./columnbar.mjs";
67
68
  import "./filter-button.mjs";
68
69
  import {
69
- findElementWithSelectorUpwards,
70
- getDocument,
71
- getWindow,
70
+ findElementWithSelectorUpwards,
71
+ getDocument,
72
+ getWindow,
72
73
  } 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";
74
+ import {addAttributeToken} from "../../dom/attributes.mjs";
75
+ import {ATTRIBUTE_ERRORMESSAGE} from "../../dom/constants.mjs";
76
+ import {getDocumentTranslations} from "../../i18n/translations.mjs";
76
77
  import "../state/state.mjs";
77
78
  import "../host/collapse.mjs";
78
- import { generateUniqueConfigKey } from "../host/util.mjs";
79
+ import {generateUniqueConfigKey} from "../host/util.mjs";
79
80
 
80
81
  import "./datasource/dom.mjs";
81
82
  import "./datasource/rest.mjs";
82
83
 
83
84
  import "../form/context-help.mjs";
85
+ import {getLocaleOfDocument} from "../../dom/locale.mjs";
84
86
 
85
- export { DataTable };
87
+
88
+ export {DataTable};
86
89
 
87
90
  /**
88
91
  * @private
@@ -133,423 +136,440 @@ const resizeObserverSymbol = Symbol("resizeObserver");
133
136
  *
134
137
  * @fragments /fragments/components/datatable/datatable/
135
138
  *
136
- * @example /examples/components/datatable/empty
137
- * @example /examples/components/datatable/data-using-javascript
138
- * @example /examples/components/datatable/alignment
139
- * @example /examples/components/datatable/row-mode
140
- * @example /examples/components/datatable/grid-template
141
- * @example /examples/components/datatable/overview-class
142
- * @example /examples/components/datatable/datasource
143
- * @example /examples/components/datatable/pagination
144
- * @example /examples/components/datatable/filter
139
+ * @example /examples/components/datatable/empty The empty state
140
+ * @example /examples/components/datatable/data-using-javascript The data using javascript
141
+ * @example /examples/components/datatable/alignment The alignment
142
+ * @example /examples/components/datatable/row-mode The row mode
143
+ * @example /examples/components/datatable/grid-template The grid template
144
+ * @example /examples/components/datatable/overview-class The overview class
145
+ * @example /examples/components/datatable/datasource Use a datasource
146
+ * @example /examples/components/datatable/pagination Use pagination
147
+ * @example /examples/components/datatable/filter Filer the data
148
+ * @example /examples/components/datatable/ Select rows
145
149
  *
146
150
  * @copyright schukai GmbH
147
151
  * @summary A beautiful and highly customizable data table. It can be used to display data from a data source.
148
152
  * @fires monster-datatable-row-copied
149
153
  * @fires monster-datatable-row-removed
150
154
  * @fires monster-datatable-row-added
155
+ * @fires monster-datatable-row-selected
156
+ * @fires monster-datatable-row-deselected
157
+ * @fires monster-datatable-all-rows-selected
158
+ * @fires monster-datatable-all-rows-deselected
159
+ * @fires monster-datatable-selection-changed
151
160
  **/
152
161
  class DataTable extends CustomElement {
153
- /**
154
- * This method is called by the `instanceof` operator.
155
- * @return {symbol}
156
- */
157
- static get [instanceSymbol]() {
158
- return Symbol.for("@schukai/monster/components/datatable@@instance");
159
- }
160
-
161
- /**
162
- * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
163
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
164
- *
165
- * The individual configuration values can be found in the table.
166
- *
167
- * @property {Object} templates Template definitions
168
- * @property {string} templates.main Main template
169
- * @property {Object} datasource Datasource configuration
170
- * @property {string} datasource.selector Selector for the datasource
171
- * @property {Object} mapping Mapping configuration
172
- * @property {string} mapping.data Data mapping
173
- * @property {Array} data Data
174
- * @property {Array} headers Headers
175
- * @property {Object} responsive Responsive configuration
176
- * @property {number} responsive.breakpoint Breakpoint for responsive mode
177
- * @property {Object} labels Labels
178
- * @property {string} labels.theListContainsNoEntries Label for empty state
179
- * @property {Object} classes Classes
180
- * @property {string} classes.container Container class
181
- * @property {Object} features Features
182
- * @property {boolean} features.settings Settings feature
183
- * @property {boolean} features.footer Footer feature
184
- * @property {boolean} features.autoInit Auto init feature (init datasource automatically)
185
- * @property {boolean} features.doubleClickCopyToClipboard Double click copy to clipboard feature
186
- * @property {boolean} features.copyAll Copy all feature
187
- * @property {boolean} features.help Help feature
188
- * @property {Object} templateMapping Template mapping
189
- * @property {string} templateMapping.row-key Row key
190
- * @property {string} templateMapping.filter-id Filter id
191
- **/
192
- get defaults() {
193
- return Object.assign(
194
- {},
195
- super.defaults,
196
- {
197
- templates: {
198
- main: getTemplate(),
199
- emptyState: getEmptyTemplate(),
200
- },
201
-
202
- datasource: {
203
- selector: null,
204
- },
205
-
206
- mapping: {
207
- data: "dataset",
208
- },
209
-
210
- data: [],
211
- headers: [],
212
-
213
- responsive: {
214
- breakpoint: 900,
215
- },
216
-
217
- labels: {
218
- theListContainsNoEntries: "The list contains no entries",
219
- copyAll: "Copy all",
220
- helpText:
221
- "<p>You can copy the values from individual rows<br>" +
222
- "to the clipboard by double-clicking on the relevant column.</p>" +
223
- "<p>To copy an entire row, hold down the Shift key while clicking.<br>" +
224
- "If you want to copy all rows, you can use the <strong>Copy All</strong> button.</p>",
225
- },
226
-
227
- classes: {
228
- control: "monster-theme-control-container-1",
229
- container: "",
230
- row: "monster-theme-control-row-1",
231
- },
232
-
233
- features: {
234
- settings: true,
235
- footer: true,
236
- autoInit: true,
237
- doubleClickCopyToClipboard: true,
238
- copyAll: true,
239
- help: true,
240
- },
241
-
242
- copy: {
243
- delimiter: ";",
244
- quoteOpen: '"',
245
- quoteClose: '"',
246
- rowBreak: "\n",
247
- },
248
-
249
- templateMapping: {
250
- "row-key": null,
251
- "filter-id": null,
252
- },
253
- },
254
- initOptionsFromArguments.call(this),
255
- );
256
- }
257
-
258
- /**
259
- *
260
- * @param {string} selector
261
- * @return {NodeListOf<*>}
262
- */
263
- getGridElements(selector) {
264
- return this[gridElementSymbol].querySelectorAll(selector);
265
- }
266
-
267
- /**
268
- *
269
- * @return {string}
270
- */
271
- static getTag() {
272
- return "monster-datatable";
273
- }
274
-
275
- /**
276
- * @return {void}
277
- */
278
- disconnectedCallback() {
279
- super.disconnectedCallback();
280
- if (this?.[resizeObserverSymbol] instanceof ResizeObserver) {
281
- this[resizeObserverSymbol].disconnect();
282
- }
283
- }
284
-
285
- /**
286
- * @return {void}
287
- */
288
- connectedCallback() {
289
- const self = this;
290
- super.connectedCallback();
291
-
292
- this[resizeObserverSymbol] = new ResizeObserver((entries) => {
293
- updateGrid.call(self);
294
- });
295
-
296
- this[resizeObserverSymbol].observe(this.parentNode);
297
- }
298
-
299
- /**
300
- * @return void
301
- */
302
- [assembleMethodSymbol]() {
303
- const rawKey = this.getOption("templateMapping.row-key");
304
-
305
- if (rawKey === null) {
306
- if (this.id !== null && this.id !== "") {
307
- const rawKey = this.getOption("templateMapping.row-key");
308
- if (rawKey === null) {
309
- this.setOption("templateMapping.row-key", this.id + "-row");
310
- }
311
- } else {
312
- this.setOption("templateMapping.row-key", "row");
313
- }
314
- }
315
-
316
- if (this.id !== null && this.id !== "") {
317
- this.setOption("templateMapping.filter-id", "" + this.id + "-filter");
318
- } else {
319
- this.setOption("templateMapping.filter-id", "filter");
320
- }
321
-
322
- super[assembleMethodSymbol]();
323
-
324
- initControlReferences.call(this);
325
- initEventHandler.call(this);
326
-
327
- const selector = this.getOption("datasource.selector");
328
-
329
- if (isString(selector)) {
330
- const element = findElementWithSelectorUpwards(this, selector);
331
- if (element === null) {
332
- throw new Error("the selector must match exactly one element");
333
- }
334
-
335
- if (!isInstance(element, Datasource)) {
336
- throw new TypeError("the element must be a datasource");
337
- }
338
-
339
- this[datasourceLinkedElementSymbol] = element;
340
-
341
- queueMicrotask(() => {
342
- handleDataSourceChanges.call(this);
343
- element.datasource.attachObserver(
344
- new Observer(handleDataSourceChanges.bind(this)),
345
- );
346
- });
347
- }
348
-
349
- getHostConfig
350
- .call(this, getColumnVisibilityConfigKey)
351
- .then((config) => {
352
- const headerOrderMap = new Map();
353
-
354
- getHostConfig
355
- .call(this, getStoredOrderConfigKey)
356
- .then((orderConfig) => {
357
- if (isArray(orderConfig) || orderConfig.length > 0) {
358
- for (let i = 0; i < orderConfig.length; i++) {
359
- const item = orderConfig[i];
360
- const parts = item.split(" ");
361
- const field = parts[0];
362
- const direction = parts[1] || DIRECTION_ASC;
363
- headerOrderMap.set(field, direction);
364
- }
365
- }
366
- })
367
- .then(() => {
368
- try {
369
- initGridAndStructs.call(this, config, headerOrderMap);
370
- } catch (error) {
371
- addAttributeToken(
372
- this,
373
- ATTRIBUTE_ERRORMESSAGE,
374
- error?.message || error.toString(),
375
- );
376
- }
377
-
378
- updateColumnBar.call(this);
379
- })
380
- .catch((error) => {
381
- addAttributeToken(
382
- this,
383
- ATTRIBUTE_ERRORMESSAGE,
384
- error?.message || error.toString(),
385
- );
386
- });
387
- })
388
- .catch((error) => {
389
- addAttributeToken(
390
- this,
391
- ATTRIBUTE_ERRORMESSAGE,
392
- error?.message || error.toString(),
393
- );
394
- });
395
- }
396
-
397
- /**
398
- * @return {CSSStyleSheet[]}
399
- */
400
- static getCSSStyleSheet() {
401
- return [DatatableStyleSheet];
402
- }
403
-
404
- /**
405
- * Copy a row from the datatable
406
- *
407
- * @param {number|string} fromIndex
408
- * @param {number|string} toIndex
409
- * @return {DataTable}
410
- * @fires monster-datatable-row-copied
411
- */
412
- copyRow(fromIndex, toIndex) {
413
- const datasource = this[datasourceLinkedElementSymbol];
414
- if (!datasource) {
415
- return this;
416
- }
417
- let d = datasource.data;
418
- let c = clone(d);
419
-
420
- let rows = c;
421
- const mapping = this.getOption("mapping.data");
422
-
423
- if (mapping) {
424
- rows = c?.[mapping];
425
- }
426
-
427
- if (rows === undefined || rows === null) {
428
- rows = [];
429
- }
430
-
431
- if (toIndex === undefined) {
432
- toIndex = rows.length;
433
- }
434
-
435
- if (isString(fromIndex)) {
436
- fromIndex = parseInt(fromIndex);
437
- }
438
- if (isString(toIndex)) {
439
- toIndex = parseInt(toIndex);
440
- }
441
-
442
- if (toIndex < 0 || toIndex > rows.length) {
443
- throw new RangeError("index out of bounds");
444
- }
445
-
446
- validateArray(rows);
447
- validateInteger(fromIndex);
448
- validateInteger(toIndex);
449
-
450
- if (fromIndex < 0 || fromIndex >= rows.length) {
451
- throw new RangeError("index out of bounds");
452
- }
453
-
454
- rows.splice(toIndex, 0, clone(rows[fromIndex]));
455
- datasource.data = c;
456
-
457
- fireCustomEvent(this, "monster-datatable-row-copied", {
458
- index: toIndex,
459
- });
460
-
461
- return this;
462
- }
463
-
464
- /**
465
- * Remove a row from the datatable
466
- *
467
- * @param {number|string} index
468
- * @return {DataTable}
469
- * @fires monster-datatable-row-removed
470
- */
471
- removeRow(index) {
472
- const datasource = this[datasourceLinkedElementSymbol];
473
- if (!datasource) {
474
- return this;
475
- }
476
- let d = datasource.data;
477
- let c = clone(d);
478
-
479
- let rows = c;
480
- const mapping = this.getOption("mapping.data");
481
-
482
- if (mapping) {
483
- rows = c?.[mapping];
484
- }
485
-
486
- if (rows === undefined || rows === null) {
487
- rows = [];
488
- }
489
-
490
- if (isString(index)) {
491
- index = parseInt(index);
492
- }
493
-
494
- validateArray(rows);
495
- validateInteger(index);
496
-
497
- if (index < 0 || index >= rows.length) {
498
- throw new RangeError("index out of bounds");
499
- }
500
- if (mapping) {
501
- rows = c?.[mapping];
502
- }
503
-
504
- rows.splice(index, 1);
505
- datasource.data = c;
506
-
507
- fireCustomEvent(this, "monster-datatable-row-removed", {
508
- index: index,
509
- });
510
-
511
- return this;
512
- }
513
-
514
- /**
515
- * Add a row to the datatable
516
- *
517
- * @param {Object} data
518
- * @return {DataTable}
519
- *
520
- * @fires monster-datatable-row-added
521
- **/
522
- addRow(data) {
523
- const datasource = this[datasourceLinkedElementSymbol];
524
- if (!datasource) {
525
- return this;
526
- }
527
- let d = datasource.data;
528
- let c = clone(d);
529
-
530
- let rows = c;
531
-
532
- const mapping = this.getOption("mapping.data");
533
- if (mapping) {
534
- rows = c?.[mapping];
535
- }
536
-
537
- if (rows === undefined || rows === null) {
538
- rows = [];
539
- }
540
-
541
- validateArray(rows);
542
- validateObject(data);
543
-
544
- rows.push(data);
545
- datasource.data = c;
546
-
547
- fireCustomEvent(this, "monster-datatable-row-added", {
548
- index: rows.length - 1,
549
- });
550
-
551
- return this;
552
- }
162
+ /**
163
+ * This method is called by the `instanceof` operator.
164
+ * @return {symbol}
165
+ */
166
+ static get [instanceSymbol]() {
167
+ return Symbol.for("@schukai/monster/components/datatable@@instance");
168
+ }
169
+
170
+ /**
171
+ * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
172
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
173
+ *
174
+ * The individual configuration values can be found in the table.
175
+ *
176
+ * @property {Object} templates Template definitions
177
+ * @property {string} templates.main Main template
178
+ * @property {Object} datasource Datasource configuration
179
+ * @property {string} datasource.selector Selector for the datasource
180
+ * @property {Object} mapping Mapping configuration
181
+ * @property {string} mapping.data Data mapping
182
+ * @property {Array} data Data
183
+ * @property {Array} headers Headers
184
+ * @property {Object} responsive Responsive configuration
185
+ * @property {number} responsive.breakpoint Breakpoint for responsive mode
186
+ * @property {Object} labels Labels
187
+ * @property {string} labels.theListContainsNoEntries Label for empty state
188
+ * @property {Object} classes Classes
189
+ * @property {string} classes.container Container class
190
+ * @property {Object} features Features
191
+ * @property {boolean} features.settings Settings feature
192
+ * @property {boolean} features.footer Footer feature
193
+ * @property {boolean} features.autoInit Auto init feature (init datasource automatically)
194
+ * @property {boolean} features.doubleClickCopyToClipboard Double click copy to clipboard feature
195
+ * @property {boolean} features.copyAll Copy all feature
196
+ * @property {boolean} features.help Help feature
197
+ * @property {Object} templateMapping Template mapping
198
+ * @property {string} templateMapping.row-key Row key
199
+ * @property {string} templateMapping.filter-id Filter id
200
+ **/
201
+ get defaults() {
202
+ return Object.assign(
203
+ {},
204
+ super.defaults,
205
+ {
206
+ templates: {
207
+ main: getTemplate(),
208
+ emptyState: getEmptyTemplate(),
209
+ },
210
+
211
+ datasource: {
212
+ selector: null,
213
+ },
214
+
215
+ mapping: {
216
+ data: "dataset",
217
+ },
218
+
219
+ data: [],
220
+ headers: [],
221
+
222
+ responsive: {
223
+ breakpoint: 900,
224
+ },
225
+
226
+ labels: getTranslations(),
227
+
228
+ classes: {
229
+ control: "monster-theme-control-container-1",
230
+ container: "",
231
+ row: "monster-theme-control-row-1",
232
+ },
233
+
234
+ features: {
235
+ settings: true,
236
+ footer: true,
237
+ autoInit: true,
238
+ doubleClickCopyToClipboard: true,
239
+ copyAll: true,
240
+ help: true,
241
+ },
242
+
243
+ copy: {
244
+ delimiter: ";",
245
+ quoteOpen: '"',
246
+ quoteClose: '"',
247
+ rowBreak: "\n",
248
+ },
249
+
250
+ templateMapping: {
251
+ "row-key": null,
252
+ "filter-id": null,
253
+ },
254
+ },
255
+ initOptionsFromArguments.call(this),
256
+ );
257
+ }
258
+
259
+ /**
260
+ *
261
+ * @param {string} selector
262
+ * @return {NodeListOf<*>}
263
+ */
264
+ getGridElements(selector) {
265
+ return this[gridElementSymbol].querySelectorAll(selector);
266
+ }
267
+
268
+ /**
269
+ *
270
+ * @return {string}
271
+ */
272
+ static getTag() {
273
+ return "monster-datatable";
274
+ }
275
+
276
+ /**
277
+ * @return {void}
278
+ */
279
+ disconnectedCallback() {
280
+ super.disconnectedCallback();
281
+ if (this?.[resizeObserverSymbol] instanceof ResizeObserver) {
282
+ this[resizeObserverSymbol].disconnect();
283
+ }
284
+ }
285
+
286
+ /**
287
+ * @return {void}
288
+ */
289
+ connectedCallback() {
290
+ const self = this;
291
+ super.connectedCallback();
292
+
293
+ this[resizeObserverSymbol] = new ResizeObserver((entries) => {
294
+ updateGrid.call(self);
295
+ });
296
+
297
+ this[resizeObserverSymbol].observe(this.parentNode);
298
+ }
299
+
300
+ /**
301
+ * Get the row number of the selected rows as an array
302
+ *
303
+ * @returns {number[]}
304
+ */
305
+ getSelectedRows() {
306
+ const rows = this.getGridElements(`[data-monster-role="select-row"]`);
307
+ const selectedRows = [];
308
+ rows.forEach((row) => {
309
+ if (row.checked) {
310
+ const key = row.parentNode.getAttribute("data-monster-insert-reference");
311
+ const index = key.split("-").pop();
312
+ selectedRows.push(parseInt(index, 10));
313
+ }
314
+ });
315
+
316
+ return selectedRows;
317
+ }
318
+
319
+ /**
320
+ * @return void
321
+ */
322
+ [assembleMethodSymbol]() {
323
+ const rawKey = this.getOption("templateMapping.row-key");
324
+
325
+ if (rawKey === null) {
326
+ if (this.id !== null && this.id !== "") {
327
+ const rawKey = this.getOption("templateMapping.row-key");
328
+ if (rawKey === null) {
329
+ this.setOption("templateMapping.row-key", this.id + "-row");
330
+ }
331
+ } else {
332
+ this.setOption("templateMapping.row-key", "row");
333
+ }
334
+ }
335
+
336
+ if (this.id !== null && this.id !== "") {
337
+ this.setOption("templateMapping.filter-id", "" + this.id + "-filter");
338
+ } else {
339
+ this.setOption("templateMapping.filter-id", "filter");
340
+ }
341
+
342
+ super[assembleMethodSymbol]();
343
+
344
+ initControlReferences.call(this);
345
+ initEventHandler.call(this);
346
+
347
+ const selector = this.getOption("datasource.selector");
348
+
349
+ if (isString(selector)) {
350
+ const element = findElementWithSelectorUpwards(this, selector);
351
+ if (element === null) {
352
+ throw new Error("the selector must match exactly one element");
353
+ }
354
+
355
+ if (!isInstance(element, Datasource)) {
356
+ throw new TypeError("the element must be a datasource");
357
+ }
358
+
359
+ this[datasourceLinkedElementSymbol] = element;
360
+
361
+ queueMicrotask(() => {
362
+ handleDataSourceChanges.call(this);
363
+ element.datasource.attachObserver(
364
+ new Observer(handleDataSourceChanges.bind(this)),
365
+ );
366
+ });
367
+ }
368
+
369
+ getHostConfig
370
+ .call(this, getColumnVisibilityConfigKey)
371
+ .then((config) => {
372
+ const headerOrderMap = new Map();
373
+
374
+ getHostConfig
375
+ .call(this, getStoredOrderConfigKey)
376
+ .then((orderConfig) => {
377
+ if (isArray(orderConfig) || orderConfig.length > 0) {
378
+ for (let i = 0; i < orderConfig.length; i++) {
379
+ const item = orderConfig[i];
380
+ const parts = item.split(" ");
381
+ const field = parts[0];
382
+ const direction = parts[1] || DIRECTION_ASC;
383
+ headerOrderMap.set(field, direction);
384
+ }
385
+ }
386
+ })
387
+ .then(() => {
388
+ try {
389
+ initGridAndStructs.call(this, config, headerOrderMap);
390
+ } catch (error) {
391
+ addAttributeToken(
392
+ this,
393
+ ATTRIBUTE_ERRORMESSAGE,
394
+ error?.message || error.toString(),
395
+ );
396
+ }
397
+
398
+ updateColumnBar.call(this);
399
+ })
400
+ .catch((error) => {
401
+ addAttributeToken(
402
+ this,
403
+ ATTRIBUTE_ERRORMESSAGE,
404
+ error?.message || error.toString(),
405
+ );
406
+ });
407
+ })
408
+ .catch((error) => {
409
+ addAttributeToken(
410
+ this,
411
+ ATTRIBUTE_ERRORMESSAGE,
412
+ error?.message || error.toString(),
413
+ );
414
+ });
415
+ }
416
+
417
+ /**
418
+ * @return {CSSStyleSheet[]}
419
+ */
420
+ static getCSSStyleSheet() {
421
+ return [DatatableStyleSheet];
422
+ }
423
+
424
+ /**
425
+ * Copy a row from the datatable
426
+ *
427
+ * @param {number|string} fromIndex
428
+ * @param {number|string} toIndex
429
+ * @return {DataTable}
430
+ * @fires monster-datatable-row-copied
431
+ */
432
+ copyRow(fromIndex, toIndex) {
433
+ const datasource = this[datasourceLinkedElementSymbol];
434
+ if (!datasource) {
435
+ return this;
436
+ }
437
+ let d = datasource.data;
438
+ let c = clone(d);
439
+
440
+ let rows = c;
441
+ const mapping = this.getOption("mapping.data");
442
+
443
+ if (mapping) {
444
+ rows = c?.[mapping];
445
+ }
446
+
447
+ if (rows === undefined || rows === null) {
448
+ rows = [];
449
+ }
450
+
451
+ if (toIndex === undefined) {
452
+ toIndex = rows.length;
453
+ }
454
+
455
+ if (isString(fromIndex)) {
456
+ fromIndex = parseInt(fromIndex);
457
+ }
458
+ if (isString(toIndex)) {
459
+ toIndex = parseInt(toIndex);
460
+ }
461
+
462
+ if (toIndex < 0 || toIndex > rows.length) {
463
+ throw new RangeError("index out of bounds");
464
+ }
465
+
466
+ validateArray(rows);
467
+ validateInteger(fromIndex);
468
+ validateInteger(toIndex);
469
+
470
+ if (fromIndex < 0 || fromIndex >= rows.length) {
471
+ throw new RangeError("index out of bounds");
472
+ }
473
+
474
+ rows.splice(toIndex, 0, clone(rows[fromIndex]));
475
+ datasource.data = c;
476
+
477
+ fireCustomEvent(this, "monster-datatable-row-copied", {
478
+ index: toIndex,
479
+ });
480
+
481
+ return this;
482
+ }
483
+
484
+ /**
485
+ * Remove a row from the datatable
486
+ *
487
+ * @param {number|string} index
488
+ * @return {DataTable}
489
+ * @fires monster-datatable-row-removed
490
+ */
491
+ removeRow(index) {
492
+ const datasource = this[datasourceLinkedElementSymbol];
493
+ if (!datasource) {
494
+ return this;
495
+ }
496
+ let d = datasource.data;
497
+ let c = clone(d);
498
+
499
+ let rows = c;
500
+ const mapping = this.getOption("mapping.data");
501
+
502
+ if (mapping) {
503
+ rows = c?.[mapping];
504
+ }
505
+
506
+ if (rows === undefined || rows === null) {
507
+ rows = [];
508
+ }
509
+
510
+ if (isString(index)) {
511
+ index = parseInt(index);
512
+ }
513
+
514
+ validateArray(rows);
515
+ validateInteger(index);
516
+
517
+ if (index < 0 || index >= rows.length) {
518
+ throw new RangeError("index out of bounds");
519
+ }
520
+ if (mapping) {
521
+ rows = c?.[mapping];
522
+ }
523
+
524
+ rows.splice(index, 1);
525
+ datasource.data = c;
526
+
527
+ fireCustomEvent(this, "monster-datatable-row-removed", {
528
+ index: index,
529
+ });
530
+
531
+ return this;
532
+ }
533
+
534
+ /**
535
+ * Add a row to the datatable
536
+ *
537
+ * @param {Object} data
538
+ * @return {DataTable}
539
+ *
540
+ * @fires monster-datatable-row-added
541
+ **/
542
+ addRow(data) {
543
+ const datasource = this[datasourceLinkedElementSymbol];
544
+ if (!datasource) {
545
+ return this;
546
+ }
547
+ let d = datasource.data;
548
+ let c = clone(d);
549
+
550
+ let rows = c;
551
+
552
+ const mapping = this.getOption("mapping.data");
553
+ if (mapping) {
554
+ rows = c?.[mapping];
555
+ }
556
+
557
+ if (rows === undefined || rows === null) {
558
+ rows = [];
559
+ }
560
+
561
+ validateArray(rows);
562
+ validateObject(data);
563
+
564
+ rows.push(data);
565
+ datasource.data = c;
566
+
567
+ fireCustomEvent(this, "monster-datatable-row-added", {
568
+ index: rows.length - 1,
569
+ });
570
+
571
+ return this;
572
+ }
553
573
  }
554
574
 
555
575
  /**
@@ -557,7 +577,7 @@ class DataTable extends CustomElement {
557
577
  * @return {string}
558
578
  */
559
579
  function getColumnVisibilityConfigKey() {
560
- return generateUniqueConfigKey("datatable", this?.id, "columns-visibility");
580
+ return generateUniqueConfigKey("datatable", this?.id, "columns-visibility");
561
581
  }
562
582
 
563
583
  /**
@@ -565,7 +585,7 @@ function getColumnVisibilityConfigKey() {
565
585
  * @return {string}
566
586
  */
567
587
  function getFilterConfigKey() {
568
- return generateUniqueConfigKey("datatable", this?.id, "filter");
588
+ return generateUniqueConfigKey("datatable", this?.id, "filter");
569
589
  }
570
590
 
571
591
  /**
@@ -573,410 +593,621 @@ function getFilterConfigKey() {
573
593
  * @return {Promise}
574
594
  */
575
595
  function getHostConfig(callback) {
576
- const host = findElementWithSelectorUpwards(this, "monster-host");
577
-
578
- if (!(host && this.id)) {
579
- return Promise.resolve({});
580
- }
581
-
582
- if (!host || !isFunction(host?.getConfig)) {
583
- throw new TypeError("the host must be a monster-host");
584
- }
585
-
586
- const configKey = callback.call(this);
587
- return host.hasConfig(configKey).then((hasConfig) => {
588
- if (hasConfig) {
589
- return host.getConfig(configKey);
590
- } else {
591
- return {};
592
- }
593
- });
596
+ const host = findElementWithSelectorUpwards(this, "monster-host");
597
+
598
+ if (!host) {
599
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "no host found");
600
+ return Promise.resolve({});
601
+ }
602
+
603
+ if (!this.id) {
604
+ addAttributeToken(
605
+ this,
606
+ ATTRIBUTE_ERRORMESSAGE,
607
+ "no id found; id is required for config",
608
+ );
609
+ return Promise.resolve({});
610
+ }
611
+
612
+ if (!host || !isFunction(host?.getConfig)) {
613
+ throw new TypeError("the host must be a monster-host");
614
+ }
615
+
616
+ const configKey = callback.call(this);
617
+ return host.hasConfig(configKey).then((hasConfig) => {
618
+ if (hasConfig) {
619
+ return host.getConfig(configKey);
620
+ } else {
621
+ return {};
622
+ }
623
+ });
594
624
  }
595
625
 
596
626
  /**
597
627
  * @private
598
628
  */
599
629
  function updateColumnBar() {
600
- if (!this[columnBarElementSymbol]) {
601
- return;
602
- }
603
-
604
- const columns = [];
605
- for (const header of this.getOption("headers")) {
606
- const mode = header.getInternal("mode");
607
-
608
- if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
609
- continue;
610
- }
611
-
612
- columns.push({
613
- visible: mode !== ATTRIBUTE_DATATABLE_MODE_HIDDEN,
614
- name: header.label,
615
- index: header.index,
616
- });
617
- }
618
-
619
- this[columnBarElementSymbol].setOption("columns", columns);
630
+ if (!this[columnBarElementSymbol]) {
631
+ return;
632
+ }
633
+
634
+ const columns = [];
635
+ for (const header of this.getOption("headers")) {
636
+ const mode = header.getInternal("mode");
637
+
638
+ if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
639
+ continue;
640
+ }
641
+
642
+ columns.push({
643
+ visible: mode !== ATTRIBUTE_DATATABLE_MODE_HIDDEN,
644
+ name: header.label,
645
+ index: header.index,
646
+ });
647
+ }
648
+
649
+ this[columnBarElementSymbol].setOption("columns", columns);
620
650
  }
621
651
 
622
652
  /**
623
653
  * @private
624
654
  */
625
655
  function updateHeaderFromColumnBar() {
626
- if (!this[columnBarElementSymbol]) {
627
- return;
628
- }
656
+ if (!this[columnBarElementSymbol]) {
657
+ return;
658
+ }
629
659
 
630
- const options = this[columnBarElementSymbol].getOption("columns");
631
- if (!isArray(options)) return;
660
+ const options = this[columnBarElementSymbol].getOption("columns");
661
+ if (!isArray(options)) return;
632
662
 
633
- const invisibleMap = {};
663
+ const invisibleMap = {};
634
664
 
635
- for (let i = 0; i < options.length; i++) {
636
- const option = options[i];
637
- invisibleMap[option.index] = option.visible;
638
- }
665
+ for (let i = 0; i < options.length; i++) {
666
+ const option = options[i];
667
+ invisibleMap[option.index] = option.visible;
668
+ }
639
669
 
640
- for (const header of this.getOption("headers")) {
641
- const mode = header.getInternal("mode");
670
+ for (const header of this.getOption("headers")) {
671
+ const mode = header.getInternal("mode");
642
672
 
643
- if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
644
- continue;
645
- }
673
+ if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
674
+ continue;
675
+ }
646
676
 
647
- if (invisibleMap[header.index] === false) {
648
- header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_HIDDEN);
649
- } else {
650
- header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_VISIBLE);
651
- }
652
- }
677
+ if (invisibleMap[header.index] === false) {
678
+ header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_HIDDEN);
679
+ } else {
680
+ header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_VISIBLE);
681
+ }
682
+ }
653
683
  }
654
684
 
655
685
  /**
656
686
  * @private
657
687
  */
658
688
  function updateConfigColumnBar() {
659
- if (!this[columnBarElementSymbol]) {
660
- return;
661
- }
662
-
663
- const options = this[columnBarElementSymbol].getOption("columns");
664
- if (!isArray(options)) return;
665
-
666
- const map = {};
667
- for (let i = 0; i < options.length; i++) {
668
- const option = options[i];
669
- map[option.name] = option.visible;
670
- }
671
-
672
- const host = findElementWithSelectorUpwards(this, "monster-host");
673
- if (!(host && this.id)) {
674
- return;
675
- }
676
- const configKey = getColumnVisibilityConfigKey.call(this);
677
-
678
- try {
679
- host.setConfig(configKey, map);
680
- } catch (error) {
681
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
682
- }
689
+ if (!this[columnBarElementSymbol]) {
690
+ return;
691
+ }
692
+
693
+ const options = this[columnBarElementSymbol].getOption("columns");
694
+ if (!isArray(options)) return;
695
+
696
+ const map = {};
697
+ for (let i = 0; i < options.length; i++) {
698
+ const option = options[i];
699
+ map[option.name] = option.visible;
700
+ }
701
+
702
+ const host = findElementWithSelectorUpwards(this, "monster-host");
703
+ if (!(host && this.id)) {
704
+ return;
705
+ }
706
+ const configKey = getColumnVisibilityConfigKey.call(this);
707
+
708
+ try {
709
+ host.setConfig(configKey, map);
710
+ } catch (error) {
711
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
712
+ }
683
713
  }
684
714
 
685
715
  /**
686
716
  * @private
687
717
  */
688
718
  function initEventHandler() {
689
- const self = this;
690
-
691
- const quoteOpenChar = this.getOption("copy.quoteOpen");
692
- const quoteCloseChar = this.getOption("copy.quoteClose");
693
- const delimiterChar = this.getOption("copy.delimiter");
694
- const rowBreak = this.getOption("copy.rowBreak");
695
-
696
- self[columnBarElementSymbol].attachObserver(
697
- new Observer((e) => {
698
- updateHeaderFromColumnBar.call(self);
699
- updateGrid.call(self);
700
- updateConfigColumnBar.call(self);
701
- }),
702
- );
703
-
704
- self[gridHeadersElementSymbol].addEventListener("click", function (event) {
705
- let element = null;
706
- const datasource = self[datasourceLinkedElementSymbol];
707
- if (!datasource) {
708
- return;
709
- }
710
-
711
- element = findTargetElementFromEvent(event, ATTRIBUTE_DATATABLE_SORTABLE);
712
- if (element) {
713
- const index = element.parentNode.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
714
- const headers = self.getOption("headers");
715
-
716
- event.preventDefault();
717
-
718
- headers[index].changeDirection();
719
-
720
- queueMicrotask(function () {
721
- /** hotfix, normally this should be done via the updater, no idea why this is not possible. */
722
- element.setAttribute(
723
- ATTRIBUTE_DATATABLE_SORTABLE,
724
- `${headers[index].field} ${headers[index].direction}`,
725
- );
726
-
727
- storeOrderStatement.call(self, true);
728
- });
729
- }
730
- });
731
-
732
- const eventHandlerDoubleClickCopyToClipboard = (event) => {
733
- const element = findTargetElementFromEvent(event, "data-monster-head");
734
- if (element) {
735
- let text = "";
736
-
737
- if (event.shiftKey) {
738
- const index = element.getAttribute("data-monster-insert-reference");
739
- if (index) {
740
- const cols = self.getGridElements(
741
- `[data-monster-insert-reference="${index}"]`,
742
- );
743
-
744
- const colTexts = [];
745
- for (let i = 0; i < cols.length; i++) {
746
- const col = cols[i];
747
-
748
- if (
749
- col.querySelector("monster-button-bar") ||
750
- col.querySelector("monster-button")
751
- ) {
752
- continue;
753
- }
754
-
755
- if (col.textContent) {
756
- colTexts.push(
757
- quoteOpenChar + col.textContent.trim() + quoteCloseChar,
758
- );
759
- }
760
- }
761
-
762
- text = colTexts.join(delimiterChar);
763
- }
764
- } else {
765
- if (
766
- element.querySelector("monster-button-bar") ||
767
- element.querySelector("monster-button")
768
- ) {
769
- return;
770
- }
771
-
772
- text = element.textContent.trim();
773
- }
774
-
775
- if (getWindow().navigator.clipboard && text) {
776
- getWindow()
777
- .navigator.clipboard.writeText(text)
778
- .then(
779
- () => {},
780
- (err) => {},
781
- );
782
- }
783
- }
784
- };
785
-
786
- if (self.getOption("features.doubleClickCopyToClipboard")) {
787
- self[gridElementSymbol].addEventListener(
788
- "dblclick",
789
- eventHandlerDoubleClickCopyToClipboard,
790
- );
791
- }
792
-
793
- if (self.getOption("features.copyAll") && this[copyAllElementSymbol]) {
794
- this[copyAllElementSymbol].addEventListener("click", (event) => {
795
- event.preventDefault();
796
-
797
- const table = [];
798
- let currentRow = [];
799
- let currentIndex = null;
800
-
801
- const cols = self.getGridElements(`[data-monster-insert-reference]`);
802
- const rowIndexes = new Map();
803
- cols.forEach((col) => {
804
- const index = col.getAttribute("data-monster-insert-reference");
805
- rowIndexes.set(index, true);
806
- });
807
-
808
- rowIndexes.forEach((value, key) => {
809
- const cols = self.getGridElements(
810
- `[data-monster-insert-reference="${key}"]`,
811
- );
812
-
813
- for (let i = 0; i < cols.length; i++) {
814
- const col = cols[i];
815
-
816
- if (
817
- col.querySelector("monster-button-bar") ||
818
- col.querySelector("monster-button")
819
- ) {
820
- continue;
821
- }
822
-
823
- if (col.textContent) {
824
- currentRow.push(
825
- quoteOpenChar + col.textContent.trim() + quoteCloseChar,
826
- );
827
- }
828
- }
829
-
830
- if (currentRow.length > 0) {
831
- table.push(currentRow);
832
- }
833
- currentRow = [];
834
- });
835
-
836
- if (table.length > 0) {
837
- const text = table.map((row) => row.join(delimiterChar)).join(rowBreak);
838
- if (getWindow().navigator.clipboard && text) {
839
- getWindow()
840
- .navigator.clipboard.writeText(text)
841
- .then(
842
- () => {},
843
- (err) => {},
844
- );
845
- }
846
- }
847
- });
848
- }
719
+ const self = this;
720
+
721
+ const quoteOpenChar = this.getOption("copy.quoteOpen");
722
+ const quoteCloseChar = this.getOption("copy.quoteClose");
723
+ const delimiterChar = this.getOption("copy.delimiter");
724
+ const rowBreak = this.getOption("copy.rowBreak");
725
+
726
+ self[columnBarElementSymbol].attachObserver(
727
+ new Observer((e) => {
728
+ updateHeaderFromColumnBar.call(self);
729
+ updateGrid.call(self);
730
+ updateConfigColumnBar.call(self);
731
+ }),
732
+ );
733
+
734
+ self[gridHeadersElementSymbol].addEventListener("click", function (event) {
735
+ let element = null;
736
+ const datasource = self[datasourceLinkedElementSymbol];
737
+ if (!datasource) {
738
+ return;
739
+ }
740
+
741
+ element = findTargetElementFromEvent(event, ATTRIBUTE_DATATABLE_SORTABLE);
742
+ if (element) {
743
+ const index = element.parentNode.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
744
+ const headers = self.getOption("headers");
745
+
746
+ event.preventDefault();
747
+
748
+ headers[index].changeDirection();
749
+
750
+ queueMicrotask(function () {
751
+ /** hotfix, normally this should be done via the updater, no idea why this is not possible. */
752
+ element.setAttribute(
753
+ ATTRIBUTE_DATATABLE_SORTABLE,
754
+ `${headers[index].field} ${headers[index].direction}`,
755
+ );
756
+
757
+ storeOrderStatement.call(self, true);
758
+ });
759
+ }
760
+ });
761
+
762
+ const eventHandlerDoubleClickCopyToClipboard = (event) => {
763
+ const element = findTargetElementFromEvent(event, "data-monster-head");
764
+ if (element) {
765
+ let text = "";
766
+
767
+ if (event.shiftKey) {
768
+ const index = element.getAttribute("data-monster-insert-reference");
769
+ if (index) {
770
+ const cols = self.getGridElements(
771
+ `[data-monster-insert-reference="${index}"]`,
772
+ );
773
+
774
+ const colTexts = [];
775
+ for (let i = 0; i < cols.length; i++) {
776
+ const col = cols[i];
777
+
778
+ if (
779
+ col.querySelector("monster-button-bar") ||
780
+ col.querySelector("monster-button")
781
+ ) {
782
+ continue;
783
+ }
784
+
785
+ if (col.textContent) {
786
+ colTexts.push(
787
+ quoteOpenChar + col.textContent.trim() + quoteCloseChar,
788
+ );
789
+ }
790
+ }
791
+
792
+ text = colTexts.join(delimiterChar);
793
+ }
794
+ } else {
795
+ if (
796
+ element.querySelector("monster-button-bar") ||
797
+ element.querySelector("monster-button")
798
+ ) {
799
+ return;
800
+ }
801
+
802
+ text = element.textContent.trim();
803
+ }
804
+
805
+ if (getWindow().navigator.clipboard && text) {
806
+ getWindow()
807
+ .navigator.clipboard.writeText(text)
808
+ .then(
809
+ () => {
810
+ },
811
+ (err) => {
812
+ },
813
+ );
814
+ }
815
+ }
816
+ };
817
+
818
+ if (self.getOption("features.doubleClickCopyToClipboard")) {
819
+ self[gridElementSymbol].addEventListener(
820
+ "dblclick",
821
+ eventHandlerDoubleClickCopyToClipboard,
822
+ );
823
+ }
824
+
825
+ if (self.getOption("features.copyAll") && this[copyAllElementSymbol]) {
826
+ this[copyAllElementSymbol].addEventListener("click", (event) => {
827
+ event.preventDefault();
828
+
829
+ const table = [];
830
+ let currentRow = [];
831
+ let currentIndex = null;
832
+
833
+ const cols = self.getGridElements(`[data-monster-insert-reference]`);
834
+ const rowIndexes = new Map();
835
+ cols.forEach((col) => {
836
+ const index = col.getAttribute("data-monster-insert-reference");
837
+ rowIndexes.set(index, true);
838
+ });
839
+
840
+ rowIndexes.forEach((value, key) => {
841
+ const cols = self.getGridElements(
842
+ `[data-monster-insert-reference="${key}"]`,
843
+ );
844
+
845
+ for (let i = 0; i < cols.length; i++) {
846
+ const col = cols[i];
847
+
848
+ if (
849
+ col.querySelector("monster-button-bar") ||
850
+ col.querySelector("monster-button")
851
+ ) {
852
+ continue;
853
+ }
854
+
855
+ if (col.textContent) {
856
+ currentRow.push(
857
+ quoteOpenChar + col.textContent.trim() + quoteCloseChar,
858
+ );
859
+ }
860
+ }
861
+
862
+ if (currentRow.length > 0) {
863
+ table.push(currentRow);
864
+ }
865
+ currentRow = [];
866
+ });
867
+
868
+ if (table.length > 0) {
869
+ const text = table.map((row) => row.join(delimiterChar)).join(rowBreak);
870
+ if (getWindow().navigator.clipboard && text) {
871
+ getWindow()
872
+ .navigator.clipboard.writeText(text)
873
+ .then(
874
+ () => {
875
+ },
876
+ (err) => {
877
+ },
878
+ );
879
+ }
880
+ }
881
+ });
882
+ }
883
+
884
+ const selectRowCallback = (event) => {
885
+ const element = findTargetElementFromEvent(event, "data-monster-role", "select-row");
886
+ if (element) {
887
+ const key = element.parentNode.getAttribute("data-monster-insert-reference");
888
+ const row = self.getGridElements(
889
+ `[data-monster-insert-reference="${key}"]`,
890
+ );
891
+
892
+ const index = key.split("-").pop();
893
+
894
+ if (element.checked) {
895
+ row.forEach((col) => {
896
+ col.classList.add("selected");
897
+ });
898
+
899
+ fireCustomEvent(self, "monster-datatable-row-selected", {
900
+ index: index
901
+ })
902
+
903
+ } else {
904
+ row.forEach((col) => {
905
+ col.classList.remove("selected");
906
+ });
907
+
908
+ fireCustomEvent(self, "monster-datatable-row-deselected", {
909
+ index: index
910
+ })
911
+ }
912
+
913
+ fireCustomEvent(this, "monster-datatable-selection-changed", {})
914
+ }
915
+
916
+ const rows = self.getGridElements(`[data-monster-role="select-row"]`);
917
+ const allSelected = Array.from(rows).every((row) => row.checked);
918
+ const selectAll = this[gridHeadersElementSymbol].querySelector(`[data-monster-role="select-all"]`);
919
+ selectAll.checked = allSelected;
920
+
921
+
922
+ }
923
+
924
+ this[gridElementSymbol].addEventListener("click", selectRowCallback);
925
+ this[gridElementSymbol].addEventListener("touch", selectRowCallback);
926
+
927
+ const selectAllCallback = (event) => {
928
+ const element = findTargetElementFromEvent(event, "data-monster-role", "select-all");
929
+ if (element) {
930
+ const mode = element.checked
931
+
932
+ const rows = this.getGridElements(`[data-monster-role="select-row"]`);
933
+ rows.forEach((row) => {
934
+ row.checked = mode;
935
+ });
936
+
937
+ if (mode) {
938
+ fireCustomEvent(this, "monster-datatable-all-rows-selected", {})
939
+ } else {
940
+ fireCustomEvent(this, "monster-datatable-all-rows-deselected", {})
941
+ }
942
+
943
+ fireCustomEvent(this, "monster-datatable-selection-changed", {})
944
+
945
+ }
946
+ }
947
+
948
+ this[gridHeadersElementSymbol].addEventListener("click", selectAllCallback)
949
+ this[gridHeadersElementSymbol].addEventListener("touch", selectAllCallback)
950
+
951
+
849
952
  }
850
953
 
851
954
  /**
852
955
  * @private
853
956
  */
854
957
  function initGridAndStructs(hostConfig, headerOrderMap) {
855
- const rowID = this.getOption("templateMapping.row-key");
856
-
857
- if (!this[gridElementSymbol]) {
858
- throw new Error("no grid element is defined");
859
- }
860
-
861
- let template;
862
- getSlottedElements.call(this).forEach((e) => {
863
- if (e instanceof HTMLTemplateElement && e.id === rowID) {
864
- template = e;
865
- }
866
- });
867
-
868
- if (!template) {
869
- throw new Error("no template is defined");
870
- }
871
-
872
- const rowCount = template.content.children.length;
873
-
874
- const headers = [];
875
-
876
- for (let i = 0; i < rowCount; i++) {
877
- let hClass = "";
878
- const row = template.content.children[i];
879
-
880
- let mode = "";
881
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_MODE)) {
882
- mode = row.getAttribute(ATTRIBUTE_DATATABLE_MODE);
883
- }
884
-
885
- let grid = row.getAttribute(ATTRIBUTE_DATATABLE_GRID_TEMPLATE);
886
- if (!grid || grid === "" || grid === "auto") {
887
- grid = "minmax(0, 1fr)";
888
- }
889
-
890
- let label = "";
891
- let labelKey = "";
892
-
893
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_HEAD)) {
894
- label = row.getAttribute(ATTRIBUTE_DATATABLE_HEAD);
895
- labelKey = label;
896
-
897
- try {
898
- if (label.startsWith("i18n:")) {
899
- label = label.substring(5, label.length);
900
- label = getDocumentTranslations().getText(label, label);
901
- }
902
- } catch (e) {
903
- label = "i18n error " + label;
904
- }
905
- }
906
-
907
- if (!label) {
908
- label = i + 1 + "";
909
- mode = ATTRIBUTE_DATATABLE_MODE_FIXED;
910
- labelKey = label;
911
- }
912
-
913
- if (isObject(hostConfig) && hostConfig.hasOwnProperty(label)) {
914
- if (hostConfig[label] === false) {
915
- mode = ATTRIBUTE_DATATABLE_MODE_HIDDEN;
916
- } else {
917
- mode = ATTRIBUTE_DATATABLE_MODE_VISIBLE;
918
- }
919
- }
920
-
921
- let align = "";
922
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_ALIGN)) {
923
- align = row.getAttribute(ATTRIBUTE_DATATABLE_ALIGN);
924
- }
925
-
926
- switch (align) {
927
- case "center":
928
- hClass = "flex-center";
929
- break;
930
- case "end":
931
- hClass = "flex-end";
932
- break;
933
- case "start":
934
- hClass = "flex-start";
935
- break;
936
- default:
937
- hClass = "flex-start";
938
- }
939
-
940
- let field = "";
941
- let direction = DIRECTION_NONE;
942
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_SORTABLE)) {
943
- field = row.getAttribute(ATTRIBUTE_DATATABLE_SORTABLE).trim();
944
- const parts = field.split(" ").map((item) => item.trim());
945
- field = parts[0];
946
-
947
- if (headerOrderMap.has(field)) {
948
- direction = headerOrderMap.get(field);
949
- } else if (
950
- parts.length === 2 &&
951
- [DIRECTION_ASC, DIRECTION_DESC].indexOf(parts[1]) !== -1
952
- ) {
953
- direction = parts[1];
954
- }
955
- }
956
-
957
- if (mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
958
- hClass += " hidden";
959
- }
960
-
961
- const header = new Header();
962
- header.setInternals({
963
- field: field,
964
- label: label,
965
- classes: hClass,
966
- index: i,
967
- mode: mode,
968
- grid: grid,
969
- labelKey: labelKey,
970
- direction: direction,
971
- });
972
-
973
- headers.push(header);
974
- }
975
-
976
- this.setOption("headers", headers);
977
- queueMicrotask(() => {
978
- storeOrderStatement.call(this, this.getOption("features.autoInit"));
979
- });
958
+ const rowID = this.getOption("templateMapping.row-key");
959
+
960
+ if (!this[gridElementSymbol]) {
961
+ throw new Error("no grid element is defined");
962
+ }
963
+
964
+ let template;
965
+ getSlottedElements.call(this).forEach((e) => {
966
+
967
+ if (e instanceof HTMLTemplateElement && e.id === rowID) {
968
+ template = e;
969
+ }
970
+ });
971
+
972
+ if (!template) {
973
+ throw new Error("no template is defined");
974
+ }
975
+
976
+ const rowCount = template.content.children.length;
977
+
978
+ const headers = [];
979
+
980
+ for (let i = 0; i < rowCount; i++) {
981
+ let hClass = "";
982
+ const row = template.content.children[i];
983
+
984
+ let mode = "";
985
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_MODE)) {
986
+ mode = row.getAttribute(ATTRIBUTE_DATATABLE_MODE);
987
+ }
988
+
989
+ let grid = row.getAttribute(ATTRIBUTE_DATATABLE_GRID_TEMPLATE);
990
+ if (!grid || grid === "" || grid === "auto") {
991
+ grid = "minmax(0, 1fr)";
992
+ }
993
+
994
+ let label = "";
995
+ let labelKey = "";
996
+
997
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_HEAD)) {
998
+ label = row.getAttribute(ATTRIBUTE_DATATABLE_HEAD);
999
+ labelKey = label;
1000
+
1001
+ try {
1002
+ if (label.startsWith("i18n:")) {
1003
+ label = label.substring(5, label.length);
1004
+ label = getDocumentTranslations().getText(label, label);
1005
+ }
1006
+ } catch (e) {
1007
+ label = "i18n error " + label;
1008
+ }
1009
+ }
1010
+
1011
+ if (!label) {
1012
+ label = i + 1 + "";
1013
+ mode = ATTRIBUTE_DATATABLE_MODE_FIXED;
1014
+ labelKey = label;
1015
+ }
1016
+
1017
+ if (isObject(hostConfig) && hostConfig.hasOwnProperty(label)) {
1018
+ if (hostConfig[label] === false) {
1019
+ mode = ATTRIBUTE_DATATABLE_MODE_HIDDEN;
1020
+ } else {
1021
+ mode = ATTRIBUTE_DATATABLE_MODE_VISIBLE;
1022
+ }
1023
+ }
1024
+
1025
+ let align = "";
1026
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_ALIGN)) {
1027
+ align = row.getAttribute(ATTRIBUTE_DATATABLE_ALIGN);
1028
+ }
1029
+
1030
+ switch (align) {
1031
+ case "center":
1032
+ hClass = "flex-center";
1033
+ break;
1034
+ case "end":
1035
+ hClass = "flex-end";
1036
+ break;
1037
+ case "start":
1038
+ hClass = "flex-start";
1039
+ break;
1040
+ default:
1041
+ hClass = "flex-start";
1042
+ }
1043
+
1044
+ let field = "";
1045
+ let direction = DIRECTION_NONE;
1046
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_SORTABLE)) {
1047
+ field = row.getAttribute(ATTRIBUTE_DATATABLE_SORTABLE).trim();
1048
+ const parts = field.split(" ").map((item) => item.trim());
1049
+ field = parts[0];
1050
+
1051
+ if (headerOrderMap.has(field)) {
1052
+ direction = headerOrderMap.get(field);
1053
+ } else if (
1054
+ parts.length === 2 &&
1055
+ [DIRECTION_ASC, DIRECTION_DESC].indexOf(parts[1]) !== -1
1056
+ ) {
1057
+ direction = parts[1];
1058
+ }
1059
+ }
1060
+
1061
+ if (mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
1062
+ hClass += " hidden";
1063
+ }
1064
+
1065
+ const features = [];
1066
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_FEATURES)) {
1067
+ const features = row.getAttribute(ATTRIBUTE_DATATABLE_FEATURES).split(" ");
1068
+ features.forEach((feature) => {
1069
+ features.push(feature.trim());
1070
+
1071
+ if (feature === "select") {
1072
+ label = "<input type='checkbox' data-monster-role='select-all' />";
1073
+
1074
+ while (row.firstChild) {
1075
+ row.removeChild(row.firstChild);
1076
+ }
1077
+
1078
+ const checkbox = document.createElement("input");
1079
+ checkbox.type = "checkbox";
1080
+ checkbox.setAttribute("data-monster-role", "select-row");
1081
+ row.appendChild(checkbox);
1082
+
1083
+ }
1084
+
1085
+ });
1086
+ }
1087
+
1088
+ const header = new Header();
1089
+ header.setInternals({
1090
+ field: field,
1091
+ label: label,
1092
+ classes: hClass,
1093
+ index: i,
1094
+ mode: mode,
1095
+ grid: grid,
1096
+ labelKey: labelKey,
1097
+ direction: direction,
1098
+ features: features,
1099
+ });
1100
+
1101
+ headers.push(header);
1102
+ }
1103
+
1104
+ this.setOption("headers", headers);
1105
+ queueMicrotask(() => {
1106
+ storeOrderStatement.call(this, this.getOption("features.autoInit"));
1107
+ });
1108
+ }
1109
+
1110
+ /**
1111
+ * @private
1112
+ * @returns {object}
1113
+ */
1114
+ function getTranslations() {
1115
+ const locale = getLocaleOfDocument();
1116
+ switch (locale.language) {
1117
+ case 'de':
1118
+ return {
1119
+ theListContainsNoEntries: "Die Liste enthält keine Einträge",
1120
+ copyAll: "Alles kopieren",
1121
+ helpText:
1122
+ "<p>Sie können die Werte aus einzelnen Zeilen<br>" +
1123
+ "in die Zwischenablage kopieren, indem Sie auf die entsprechende Spalte doppelklicken.</p>" +
1124
+ "<p>Um eine ganze Zeile zu kopieren, halten Sie die Umschalttaste gedrückt, während Sie klicken.<br>" +
1125
+ "Wenn Sie alle Zeilen kopieren möchten, können Sie die Schaltfläche <strong>Alles kopieren</strong> verwenden.</p>",
1126
+ };
1127
+ case 'fr':
1128
+ return {
1129
+ theListContainsNoEntries: "La liste ne contient aucune entrée",
1130
+ copyAll: "Copier tout",
1131
+ helpText:
1132
+ "<p>Vous pouvez copier les valeurs des rangées individuelles<br>" +
1133
+ "dans le presse-papiers en double-cliquant sur la colonne concernée.</p>" +
1134
+ "<p>Pour copier une rangée entière, maintenez la touche Maj enfoncée tout en cliquant.<br>" +
1135
+ "Si vous souhaitez copier toutes les rangées, vous pouvez utiliser le bouton <strong>Copier tout</strong>.</p>",
1136
+ };
1137
+ case 'sp':
1138
+ return {
1139
+ theListContainsNoEntries: "La lista no contiene entradas",
1140
+ copyAll: "Copiar todo",
1141
+ helpText:
1142
+ "<p>Puedes copiar los valores de filas individuales<br>" +
1143
+ "al portapapeles haciendo doble clic en la columna correspondiente.</p>" +
1144
+ "<p>Para copiar una fila entera, mantén presionada la tecla Shift mientras haces clic.<br>" +
1145
+ "Si quieres copiar todas las filas, puedes usar el botón <strong>Copiar todo</strong>.</p>",
1146
+ };
1147
+ case 'it':
1148
+ return {
1149
+ theListContainsNoEntries: "L'elenco non contiene voci",
1150
+ copyAll: "Copia tutto",
1151
+ helpText:
1152
+ "<p>Puoi copiare i valori dalle singole righe<br>" +
1153
+ "negli appunti facendo doppio clic sulla colonna relativa.</p>" +
1154
+ "<p>Per copiare un'intera riga, tieni premuto il tasto Shift mentre clicchi.<br>" +
1155
+ "Se vuoi copiare tutte le righe, puoi usare il pulsante <strong>Copia tutto</strong>.</p>",
1156
+ };
1157
+ case 'pl':
1158
+ return {
1159
+ theListContainsNoEntries: "Lista nie zawiera wpisów",
1160
+ copyAll: "Kopiuj wszystko",
1161
+ helpText:
1162
+ "<p>Możesz skopiować wartości z poszczególnych wierszy<br>" +
1163
+ "do schowka, klikając dwukrotnie na odpowiednią kolumnę.</p>" +
1164
+ "<p>Aby skopiować cały wiersz, przytrzymaj klawisz Shift podczas klikania.<br>" +
1165
+ "Jeśli chcesz skopiować wszystkie wiersze, możesz użyć przycisku <strong>Kopiuj wszystko</strong>.</p>",
1166
+ };
1167
+ case 'no':
1168
+ return {
1169
+ theListContainsNoEntries: "Listen inneholder ingen oppføringer",
1170
+ copyAll: "Kopier alt",
1171
+ helpText:
1172
+ "<p>Du kan kopiere verdier fra enkeltrader<br>" +
1173
+ "til utklippstavlen ved å dobbeltklikke på den relevante kolonnen.</p>" +
1174
+ "<p>For å kopiere en hel rad, hold nede Skift-tasten mens du klikker.<br>" +
1175
+ "Hvis du vil kopiere alle radene, kan du bruke knappen <strong>Kopier alt</strong>.</p>",
1176
+ };
1177
+ case 'dk':
1178
+ return {
1179
+ theListContainsNoEntries: "Listen indeholder ingen poster",
1180
+ copyAll: "Kopiér alt",
1181
+ helpText:
1182
+ "<p>Du kan kopiere værdier fra enkelte rækker<br>" +
1183
+ "til udklipsholderen ved at dobbeltklikke på den relevante kolonne.</p>" +
1184
+ "<p>For at kopiere en hel række, hold Shift-tasten nede, mens du klikker.<br>" +
1185
+ "Hvis du vil kopiere alle rækker, kan du bruge knappen <strong>Kopiér alt</strong>.</p>",
1186
+ };
1187
+ case 'sw':
1188
+ return {
1189
+ theListContainsNoEntries: "Listan innehåller inga poster",
1190
+ copyAll: "Kopiera allt",
1191
+ helpText:
1192
+ "<p>Du kan kopiera värden från enskilda rader<br>" +
1193
+ "till urklipp genom att dubbelklicka på den relevanta kolumnen.</p>" +
1194
+ "<p>För att kopiera en hel rad, håll ned Shift-tangenten medan du klickar.<br>" +
1195
+ "Om du vill kopiera alla rader kan du använda knappen <strong>Kopiera allt</strong>.</p>",
1196
+ };
1197
+
1198
+
1199
+ case 'en':
1200
+ default:
1201
+ return {
1202
+ theListContainsNoEntries: "The list contains no entries",
1203
+ copyAll: "Copy all",
1204
+ helpText:
1205
+ "<p>You can copy the values from individual rows<br>" +
1206
+ "to the clipboard by double-clicking on the relevant column.</p>" +
1207
+ "<p>To copy an entire row, hold down the Shift key while clicking.<br>" +
1208
+ "If you want to copy all rows, you can use the <strong>Copy All</strong> button.</p>",
1209
+ };
1210
+ }
980
1211
  }
981
1212
 
982
1213
  /**
@@ -984,79 +1215,79 @@ function initGridAndStructs(hostConfig, headerOrderMap) {
984
1215
  * @return {string}
985
1216
  */
986
1217
  export function getStoredOrderConfigKey() {
987
- return generateUniqueConfigKey("datatable", this?.id, "stored-order");
1218
+ return generateUniqueConfigKey("datatable", this?.id, "stored-order");
988
1219
  }
989
1220
 
990
1221
  /**
991
1222
  * @private
992
1223
  */
993
1224
  function storeOrderStatement(doFetch) {
994
- const headers = this.getOption("headers");
995
- const statement = createOrderStatement(headers);
996
- setDataSource.call(this, { orderBy: statement }, doFetch);
1225
+ const headers = this.getOption("headers");
1226
+ const statement = createOrderStatement(headers);
1227
+ setDataSource.call(this, {orderBy: statement}, doFetch);
997
1228
 
998
- const host = findElementWithSelectorUpwards(this, "monster-host");
999
- if (!(host && this.id)) {
1000
- return;
1001
- }
1229
+ const host = findElementWithSelectorUpwards(this, "monster-host");
1230
+ if (!(host && this.id)) {
1231
+ return;
1232
+ }
1002
1233
 
1003
- const configKey = getStoredOrderConfigKey.call(this);
1234
+ const configKey = getStoredOrderConfigKey.call(this);
1004
1235
 
1005
- // statement explode with , and remove all empty
1006
- const list = statement.split(",").filter((item) => item.trim() !== "");
1007
- if (list.length === 0) {
1008
- return;
1009
- }
1236
+ // statement explode with , and remove all empty
1237
+ const list = statement.split(",").filter((item) => item.trim() !== "");
1238
+ if (list.length === 0) {
1239
+ return;
1240
+ }
1010
1241
 
1011
- host.setConfig(configKey, list);
1242
+ host.setConfig(configKey, list);
1012
1243
  }
1013
1244
 
1014
1245
  /**
1015
1246
  * @private
1016
1247
  */
1017
1248
  function updateGrid() {
1018
- if (!this[gridElementSymbol]) {
1019
- throw new Error("no grid element is defined");
1020
- }
1021
-
1022
- let gridTemplateColumns = "";
1023
-
1024
- const headers = this.getOption("headers");
1025
-
1026
- let styles = "";
1027
-
1028
- for (let i = 0; i < headers.length; i++) {
1029
- const header = headers[i];
1030
-
1031
- if (header.mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
1032
- styles += `[data-monster-role=datatable]>[data-monster-head="${header.labelKey}"] { display: none; }\n`;
1033
- styles += `[data-monster-role=datatable-headers]>[data-monster-index="${header.index}"] { display: none; }\n`;
1034
- } else {
1035
- gridTemplateColumns += `${header.grid} `;
1036
- }
1037
- }
1038
-
1039
- const sheet = new CSSStyleSheet();
1040
- if (styles !== "") sheet.replaceSync(styles);
1041
- this.shadowRoot.adoptedStyleSheets = [...DataTable.getCSSStyleSheet(), sheet];
1042
-
1043
- const bodyWidth = this.parentNode.clientWidth;
1044
-
1045
- const breakpoint = this.getOption("responsive.breakpoint");
1046
- this[dataControlElementSymbol].classList.toggle(
1047
- "small",
1048
- bodyWidth <= breakpoint,
1049
- );
1050
-
1051
- if (bodyWidth > breakpoint) {
1052
- this[gridElementSymbol].style.gridTemplateColumns =
1053
- `${gridTemplateColumns}`;
1054
- this[gridHeadersElementSymbol].style.gridTemplateColumns =
1055
- `${gridTemplateColumns}`;
1056
- } else {
1057
- this[gridElementSymbol].style.gridTemplateColumns = "auto";
1058
- this[gridHeadersElementSymbol].style.gridTemplateColumns = "auto";
1059
- }
1249
+ if (!this[gridElementSymbol]) {
1250
+ throw new Error("no grid element is defined");
1251
+ }
1252
+
1253
+ let gridTemplateColumns = "";
1254
+
1255
+ const headers = this.getOption("headers");
1256
+
1257
+ let styles = "";
1258
+
1259
+ for (let i = 0; i < headers.length; i++) {
1260
+ const header = headers[i];
1261
+
1262
+ if (header.mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
1263
+ styles += `[data-monster-role=datatable]>[data-monster-head="${header.labelKey}"] { display: none; }\n`;
1264
+ styles += `[data-monster-role=datatable-headers]>[data-monster-index="${header.index}"] { display: none; }\n`;
1265
+ } else {
1266
+ gridTemplateColumns += `${header.grid} `;
1267
+ }
1268
+ }
1269
+
1270
+ const sheet = new CSSStyleSheet();
1271
+ if (styles !== "") sheet.replaceSync(styles);
1272
+ this.shadowRoot.adoptedStyleSheets = [...DataTable.getCSSStyleSheet(), sheet];
1273
+
1274
+ const bodyWidth = this.parentNode.clientWidth;
1275
+
1276
+ const breakpoint = this.getOption("responsive.breakpoint");
1277
+ this[dataControlElementSymbol].classList.toggle(
1278
+ "small",
1279
+ bodyWidth <= breakpoint,
1280
+ );
1281
+
1282
+ if (bodyWidth > breakpoint) {
1283
+ this[gridElementSymbol].style.gridTemplateColumns =
1284
+ `${gridTemplateColumns}`;
1285
+ this[gridHeadersElementSymbol].style.gridTemplateColumns =
1286
+ `${gridTemplateColumns}`;
1287
+ } else {
1288
+ this[gridElementSymbol].style.gridTemplateColumns = "auto";
1289
+ this[gridHeadersElementSymbol].style.gridTemplateColumns = "auto";
1290
+ }
1060
1291
  }
1061
1292
 
1062
1293
  /**
@@ -1064,20 +1295,20 @@ function updateGrid() {
1064
1295
  * @param {Header[]} headers
1065
1296
  * @param {bool} doFetch
1066
1297
  */
1067
- function setDataSource({ orderBy }, doFetch) {
1068
- const datasource = this[datasourceLinkedElementSymbol];
1298
+ function setDataSource({orderBy}, doFetch) {
1299
+ const datasource = this[datasourceLinkedElementSymbol];
1069
1300
 
1070
- if (!datasource) {
1071
- return;
1072
- }
1301
+ if (!datasource) {
1302
+ return;
1303
+ }
1073
1304
 
1074
- if (isFunction(datasource?.setParameters)) {
1075
- datasource.setParameters({ orderBy });
1076
- }
1305
+ if (isFunction(datasource?.setParameters)) {
1306
+ datasource.setParameters({orderBy});
1307
+ }
1077
1308
 
1078
- if (doFetch !== false && isFunction(datasource?.fetch)) {
1079
- datasource.fetch();
1080
- }
1309
+ if (doFetch !== false && isFunction(datasource?.fetch)) {
1310
+ datasource.fetch();
1311
+ }
1081
1312
  }
1082
1313
 
1083
1314
  /**
@@ -1085,28 +1316,30 @@ function setDataSource({ orderBy }, doFetch) {
1085
1316
  * @return {DataTable}
1086
1317
  */
1087
1318
  function initControlReferences() {
1088
- if (!this.shadowRoot) {
1089
- throw new Error("no shadow-root is defined");
1090
- }
1091
-
1092
- this[dataControlElementSymbol] = this.shadowRoot.querySelector(
1093
- "[data-monster-role=control]",
1094
- );
1095
-
1096
- this[gridElementSymbol] = this.shadowRoot.querySelector(
1097
- "[data-monster-role=datatable]",
1098
- );
1099
- this[gridHeadersElementSymbol] = this.shadowRoot.querySelector(
1100
- "[data-monster-role=datatable-headers]",
1101
- );
1102
- this[columnBarElementSymbol] =
1103
- this.shadowRoot.querySelector("monster-column-bar");
1104
-
1105
- this[copyAllElementSymbol] = this.shadowRoot.querySelector(
1106
- "[data-monster-role=copy-all]",
1107
- );
1108
-
1109
- return this;
1319
+ if (!this.shadowRoot) {
1320
+ throw new Error("no shadow-root is defined");
1321
+ }
1322
+
1323
+ this[dataControlElementSymbol] = this.shadowRoot.querySelector(
1324
+ "[data-monster-role=control]",
1325
+ );
1326
+
1327
+ this[gridElementSymbol] = this.shadowRoot.querySelector(
1328
+ "[data-monster-role=datatable]",
1329
+ );
1330
+
1331
+ this[gridHeadersElementSymbol] = this.shadowRoot.querySelector(
1332
+ "[data-monster-role=datatable-headers]",
1333
+ );
1334
+
1335
+ this[columnBarElementSymbol] =
1336
+ this.shadowRoot.querySelector("monster-column-bar");
1337
+
1338
+ this[copyAllElementSymbol] = this.shadowRoot.querySelector(
1339
+ "[data-monster-role=copy-all]",
1340
+ );
1341
+
1342
+ return this;
1110
1343
  }
1111
1344
 
1112
1345
  /**
@@ -1116,22 +1349,22 @@ function initControlReferences() {
1116
1349
  * @throws {Error} the datasource could not be initialized
1117
1350
  */
1118
1351
  function initOptionsFromArguments() {
1119
- const options = {};
1120
- const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
1121
-
1122
- if (selector) {
1123
- options.datasource = { selector: selector };
1124
- }
1125
-
1126
- const breakpoint = this.getAttribute(
1127
- ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
1128
- );
1129
- if (breakpoint) {
1130
- options.responsive = {};
1131
- options.responsive.breakpoint = parseInt(breakpoint);
1132
- }
1133
-
1134
- return options;
1352
+ const options = {};
1353
+ const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
1354
+
1355
+ if (selector) {
1356
+ options.datasource = {selector: selector};
1357
+ }
1358
+
1359
+ const breakpoint = this.getAttribute(
1360
+ ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
1361
+ );
1362
+ if (breakpoint) {
1363
+ options.responsive = {};
1364
+ options.responsive.breakpoint = parseInt(breakpoint);
1365
+ }
1366
+
1367
+ return options;
1135
1368
  }
1136
1369
 
1137
1370
  /**
@@ -1139,7 +1372,7 @@ function initOptionsFromArguments() {
1139
1372
  * @return {string}
1140
1373
  */
1141
1374
  function getEmptyTemplate() {
1142
- return `<monster-state data-monster-role="empty-without-action">
1375
+ return `<monster-state data-monster-role="empty-without-action">
1143
1376
  <div part="visual">
1144
1377
  <svg width="4rem" height="4rem" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
1145
1378
  <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"/>
@@ -1157,8 +1390,8 @@ function getEmptyTemplate() {
1157
1390
  * @return {string}
1158
1391
  */
1159
1392
  function getTemplate() {
1160
- // language=HTML
1161
- return `
1393
+ // language=HTML
1394
+ return `
1162
1395
  <div data-monster-role="control" part="control" data-monster-attributes="class path:classes.control">
1163
1396
  <template id="headers-row">
1164
1397
  <div data-monster-attributes="class path:headers-row.classes,
@@ -1176,7 +1409,8 @@ function getTemplate() {
1176
1409
  data-monster-attributes="class path:features.help | ?::hidden"
1177
1410
  data-monster-replace="path:labels.helpText"
1178
1411
  ></monster-context-help>
1179
- <a href="#" data-monster-attributes="class path:features.copyAll | ?::hidden" data-monster-role="copy-all" data-monster-replace="path:locale.copyAll">Copy all</a>
1412
+ <a href="#" data-monster-attributes="class path:features.copyAll | ?::hidden"
1413
+ data-monster-role="copy-all" data-monster-replace="path:labels.copyAll">Copy all</a>
1180
1414
  <monster-column-bar
1181
1415
  data-monster-attributes="class path:features.settings | ?::hidden"></monster-column-bar>
1182
1416
  <slot name="bar"></slot>