@schukai/monster 3.102.2 → 3.102.3

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