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