@schukai/monster 3.102.0 → 3.102.2

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