@schukai/monster 3.55.6 → 3.56.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/package.json +2 -2
  3. package/source/components/datatable/change-button.mjs +265 -0
  4. package/source/components/datatable/dataset.mjs +76 -5
  5. package/source/components/datatable/datasource/dom.mjs +1 -1
  6. package/source/components/datatable/datasource/rest.mjs +401 -345
  7. package/source/components/datatable/datasource.mjs +8 -0
  8. package/source/components/datatable/datatable.mjs +600 -600
  9. package/source/components/datatable/filter/range.mjs +1 -3
  10. package/source/components/datatable/filter/select.mjs +1 -1
  11. package/source/components/datatable/filter.mjs +1 -3
  12. package/source/components/datatable/save-button.mjs +301 -0
  13. package/source/components/datatable/status.mjs +6 -2
  14. package/source/components/datatable/style/change-button.pcss +19 -0
  15. package/source/components/datatable/style/save-button.pcss +44 -0
  16. package/source/components/datatable/stylesheet/change-button.mjs +27 -0
  17. package/source/components/datatable/stylesheet/save-button.mjs +27 -0
  18. package/source/components/datatable/util.mjs +3 -1
  19. package/source/components/form/button-bar.mjs +3 -3
  20. package/source/components/form/button.mjs +1 -2
  21. package/source/components/form/form.mjs +1 -1
  22. package/source/components/form/message-state-button.mjs +1 -1
  23. package/source/components/form/select.mjs +1744 -1777
  24. package/source/components/form/state-button.mjs +1 -1
  25. package/source/components/form/tabs.mjs +3 -3
  26. package/source/components/form/tree-select.mjs +6 -2
  27. package/source/components/host/overlay.mjs +4 -1
  28. package/source/components/tree-menu/tree-menu.mjs +0 -1
  29. package/source/data/datasource/server/restapi.mjs +2 -3
  30. package/source/data/datasource/server.mjs +1 -1
  31. package/source/data/extend.mjs +55 -55
  32. package/source/data/pathfinder.mjs +6 -4
  33. package/source/dom/constants.mjs +9 -0
  34. package/source/dom/customelement.mjs +25 -7
  35. package/source/dom/updater.mjs +34 -3
  36. package/source/i18n/translations.mjs +1 -1
  37. package/source/monster.mjs +0 -1
  38. package/source/types/noderecursiveiterator.mjs +2 -3
  39. package/source/types/version.mjs +1 -1
  40. package/test/cases/monster.mjs +1 -1
@@ -3,63 +3,63 @@
3
3
  * SPDX-License-Identifier: AGPL-3.0
4
4
  */
5
5
 
6
- import {Datasource} from "./datasource.mjs";
6
+ import { Datasource } from "./datasource.mjs";
7
7
  import {
8
- assembleMethodSymbol,
9
- CustomElement,
10
- registerCustomElement,
11
- getSlottedElements,
8
+ assembleMethodSymbol,
9
+ CustomElement,
10
+ registerCustomElement,
11
+ getSlottedElements,
12
12
  } from "../../dom/customelement.mjs";
13
- import {findTargetElementFromEvent} from "../../dom/events.mjs";
13
+ import { findTargetElementFromEvent } from "../../dom/events.mjs";
14
14
  import {
15
- isString,
16
- isFunction,
17
- isInstance,
18
- isObject,
19
- isArray,
15
+ isString,
16
+ isFunction,
17
+ isInstance,
18
+ isObject,
19
+ isArray,
20
20
  } from "../../types/is.mjs";
21
- import {Observer} from "../../types/observer.mjs";
21
+ import { Observer } from "../../types/observer.mjs";
22
22
  import {
23
- ATTRIBUTE_DATATABLE_HEAD,
24
- ATTRIBUTE_DATATABLE_GRID_TEMPLATE,
25
- ATTRIBUTE_DATASOURCE_SELECTOR,
26
- ATTRIBUTE_DATATABLE_ALIGN,
27
- ATTRIBUTE_DATATABLE_SORTABLE,
28
- ATTRIBUTE_DATATABLE_MODE,
29
- ATTRIBUTE_DATATABLE_INDEX,
30
- ATTRIBUTE_DATATABLE_MODE_HIDDEN,
31
- ATTRIBUTE_DATATABLE_MODE_VISIBLE,
32
- ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
33
- ATTRIBUTE_DATATABLE_MODE_FIXED,
23
+ ATTRIBUTE_DATATABLE_HEAD,
24
+ ATTRIBUTE_DATATABLE_GRID_TEMPLATE,
25
+ ATTRIBUTE_DATASOURCE_SELECTOR,
26
+ ATTRIBUTE_DATATABLE_ALIGN,
27
+ ATTRIBUTE_DATATABLE_SORTABLE,
28
+ ATTRIBUTE_DATATABLE_MODE,
29
+ ATTRIBUTE_DATATABLE_INDEX,
30
+ ATTRIBUTE_DATATABLE_MODE_HIDDEN,
31
+ ATTRIBUTE_DATATABLE_MODE_VISIBLE,
32
+ ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
33
+ ATTRIBUTE_DATATABLE_MODE_FIXED,
34
34
  } from "./constants.mjs";
35
- import {instanceSymbol} from "../../constants.mjs";
35
+ import { instanceSymbol } from "../../constants.mjs";
36
36
  import {
37
- Header,
38
- createOrderStatement,
39
- DIRECTION_ASC,
40
- DIRECTION_DESC,
41
- DIRECTION_NONE,
37
+ Header,
38
+ createOrderStatement,
39
+ DIRECTION_ASC,
40
+ DIRECTION_DESC,
41
+ DIRECTION_NONE,
42
42
  } from "./datatable/header.mjs";
43
- import {getStoredFilterConfigKey} from "./filter/util.mjs";
44
- import {DatatableStyleSheet} from "./stylesheet/datatable.mjs";
43
+ import { getStoredFilterConfigKey } from "./filter/util.mjs";
44
+ import { DatatableStyleSheet } from "./stylesheet/datatable.mjs";
45
45
  import {
46
- handleDataSourceChanges,
47
- datasourceLinkedElementSymbol,
46
+ handleDataSourceChanges,
47
+ datasourceLinkedElementSymbol,
48
48
  } from "./util.mjs";
49
49
  import "./columnbar.mjs";
50
50
  import "./filter-button.mjs";
51
- import {getDocument, getWindow} from "../../dom/util.mjs";
52
- import {addAttributeToken} from "../../dom/attributes.mjs";
53
- import {ATTRIBUTE_ERRORMESSAGE} from "../../dom/constants.mjs";
54
- import {getDocumentTranslations} from "../../i18n/translations.mjs";
51
+ import { getDocument, getWindow } from "../../dom/util.mjs";
52
+ import { addAttributeToken } from "../../dom/attributes.mjs";
53
+ import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs";
54
+ import { getDocumentTranslations } from "../../i18n/translations.mjs";
55
55
  import "../state/state.mjs";
56
56
  import "../host/collapse.mjs";
57
- import {generateUniqueConfigKey} from "../host/util.mjs";
57
+ import { generateUniqueConfigKey } from "../host/util.mjs";
58
58
 
59
59
  import "./datasource/dom.mjs";
60
60
  import "./datasource/rest.mjs";
61
61
 
62
- export {DataTable};
62
+ export { DataTable };
63
63
 
64
64
  /**
65
65
  * @private
@@ -120,209 +120,209 @@ const columnBarElementSymbol = Symbol("columnBarElement");
120
120
  * @summary A data table
121
121
  */
122
122
  class DataTable extends CustomElement {
123
- /**
124
- * This method is called by the `instanceof` operator.
125
- * @returns {symbol}
126
- */
127
- static get [instanceSymbol]() {
128
- return Symbol.for("@schukai/monster/components/datatable@@instance");
129
- }
130
-
131
- /**
132
- * To set the options via the html tag the attribute `data-monster-options` must be used.
133
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
134
- *
135
- * The individual configuration values can be found in the table.
136
- *
137
- * @property {Object} templates Template definitions
138
- * @property {string} templates.main Main template
139
- * @property {Object} datasource Datasource configuration
140
- * @property {string} datasource.selector Selector for the datasource
141
- * @property {Object} mapping Mapping configuration
142
- * @property {string} mapping.data Data mapping
143
- * @property {Array} data Data
144
- * @property {Array} headers Headers
145
- * @property {Object} responsive Responsive configuration
146
- * @property {number} responsive.breakpoint Breakpoint for responsive mode
147
- * @property {Object} labels Labels
148
- * @property {string} labels.theListContainsNoEntries Label for empty state
149
- * @property {Object} features Features
150
- * @property {boolean} features.settings Settings feature
151
- * @property {boolean} features.footer Footer feature
152
- * @property {boolean} features.autoInit Auto init feature (init datasource automatically)
153
- * @property {Object} templateMapping Template mapping
154
- * @property {string} templateMapping.row-key Row key
155
- * @property {string} templateMapping.filter-id Filter id
156
- **/
157
- get defaults() {
158
- return Object.assign(
159
- {},
160
- super.defaults,
161
- {
162
- templates: {
163
- main: getTemplate(),
164
- emptyState: getEmptyTemplate(),
165
- },
166
-
167
- datasource: {
168
- selector: null,
169
- },
170
-
171
- mapping: {
172
- data: "dataset",
173
- },
174
-
175
- data: [],
176
- headers: [],
177
-
178
- responsive: {
179
- breakpoint: 800,
180
- },
181
-
182
- labels: {
183
- theListContainsNoEntries: "The list contains no entries",
184
- },
185
-
186
- features: {
187
- settings: true,
188
- footer: true,
189
- autoInit: true,
190
- },
191
-
192
- templateMapping: {
193
- "row-key": null,
194
- "filter-id": null,
195
- },
196
- },
197
- initOptionsFromArguments.call(this),
198
- );
199
- }
200
-
201
- /**
202
- *
203
- * @param {string} selector
204
- * @returns {NodeListOf<*>}
205
- */
206
- getGridElements(selector) {
207
- return this[gridElementSymbol].querySelectorAll(selector);
208
- }
209
-
210
- /**
211
- *
212
- * @return {string}
213
- */
214
- static getTag() {
215
- return "monster-datatable";
216
- }
217
-
218
- /**
219
- *
220
- * @return {Monster.Components.Form.Form}
221
- */
222
- [assembleMethodSymbol]() {
223
- const rawKey = this.getOption("templateMapping.row-key");
224
-
225
- if (rawKey === null) {
226
- if (this.id !== null && this.id !== "") {
227
- const rawKey = this.getOption("templateMapping.row-key");
228
- if (rawKey === null) {
229
- this.setOption("templateMapping.row-key", this.id + "-row");
230
- }
231
- } else {
232
- this.setOption("templateMapping.row-key", "row");
233
- }
234
- }
235
-
236
- if (this.id !== null && this.id !== "") {
237
- this.setOption("templateMapping.filter-id", "" + this.id + "-filter");
238
- } else {
239
- this.setOption("templateMapping.filter-id", "filter");
240
- }
241
-
242
- super[assembleMethodSymbol]();
243
-
244
- initControlReferences.call(this);
245
- initEventHandler.call(this);
246
-
247
- const selector = this.getOption("datasource.selector");
248
-
249
- if (isString(selector)) {
250
- const elements = document.querySelectorAll(selector);
251
- if (elements.length !== 1) {
252
- throw new Error("the selector must match exactly one element");
253
- }
254
-
255
- const element = elements[0];
256
-
257
- if (!isInstance(element, Datasource)) {
258
- throw new TypeError("the element must be a datasource");
259
- }
260
-
261
- this[datasourceLinkedElementSymbol] = element;
262
-
263
- setTimeout(() => {
264
- handleDataSourceChanges.call(this);
265
- element.datasource.attachObserver(
266
- new Observer(handleDataSourceChanges.bind(this)),
267
- );
268
- }, 0);
269
- }
270
-
271
- getHostConfig
272
- .call(this, getColumnVisibilityConfigKey)
273
- .then((config) => {
274
- const headerOrderMap = new Map();
275
-
276
- getHostConfig
277
- .call(this, getStoredOrderConfigKey)
278
- .then((orderConfig) => {
279
- if (isArray(orderConfig) || orderConfig.length > 0) {
280
- for (let i = 0; i < orderConfig.length; i++) {
281
- const item = orderConfig[i];
282
- const parts = item.split(" ");
283
- const field = parts[0];
284
- const direction = parts[1] || DIRECTION_ASC;
285
- headerOrderMap.set(field, direction);
286
- }
287
- }
288
- })
289
- .then(() => {
290
- try {
291
- initGridAndStructs.call(this, config, headerOrderMap);
292
- } catch (error) {
293
- addAttributeToken(
294
- this,
295
- ATTRIBUTE_ERRORMESSAGE,
296
- error?.message || error.toString(),
297
- );
298
- }
299
-
300
- updateColumnBar.call(this);
301
- })
302
- .catch((error) => {
303
- addAttributeToken(
304
- this,
305
- ATTRIBUTE_ERRORMESSAGE,
306
- error?.message || error.toString(),
307
- );
308
- });
309
- })
310
- .catch((error) => {
311
- addAttributeToken(
312
- this,
313
- ATTRIBUTE_ERRORMESSAGE,
314
- error?.message || error.toString(),
315
- );
316
- });
317
- }
318
-
319
- /**
320
- *
321
- * @return {CSSStyleSheet[]}
322
- */
323
- static getCSSStyleSheet() {
324
- return [DatatableStyleSheet];
325
- }
123
+ /**
124
+ * This method is called by the `instanceof` operator.
125
+ * @returns {symbol}
126
+ */
127
+ static get [instanceSymbol]() {
128
+ return Symbol.for("@schukai/monster/components/datatable@@instance");
129
+ }
130
+
131
+ /**
132
+ * To set the options via the html tag the attribute `data-monster-options` must be used.
133
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
134
+ *
135
+ * The individual configuration values can be found in the table.
136
+ *
137
+ * @property {Object} templates Template definitions
138
+ * @property {string} templates.main Main template
139
+ * @property {Object} datasource Datasource configuration
140
+ * @property {string} datasource.selector Selector for the datasource
141
+ * @property {Object} mapping Mapping configuration
142
+ * @property {string} mapping.data Data mapping
143
+ * @property {Array} data Data
144
+ * @property {Array} headers Headers
145
+ * @property {Object} responsive Responsive configuration
146
+ * @property {number} responsive.breakpoint Breakpoint for responsive mode
147
+ * @property {Object} labels Labels
148
+ * @property {string} labels.theListContainsNoEntries Label for empty state
149
+ * @property {Object} features Features
150
+ * @property {boolean} features.settings Settings feature
151
+ * @property {boolean} features.footer Footer feature
152
+ * @property {boolean} features.autoInit Auto init feature (init datasource automatically)
153
+ * @property {Object} templateMapping Template mapping
154
+ * @property {string} templateMapping.row-key Row key
155
+ * @property {string} templateMapping.filter-id Filter id
156
+ **/
157
+ get defaults() {
158
+ return Object.assign(
159
+ {},
160
+ super.defaults,
161
+ {
162
+ templates: {
163
+ main: getTemplate(),
164
+ emptyState: getEmptyTemplate(),
165
+ },
166
+
167
+ datasource: {
168
+ selector: null,
169
+ },
170
+
171
+ mapping: {
172
+ data: "dataset",
173
+ },
174
+
175
+ data: [],
176
+ headers: [],
177
+
178
+ responsive: {
179
+ breakpoint: 800,
180
+ },
181
+
182
+ labels: {
183
+ theListContainsNoEntries: "The list contains no entries",
184
+ },
185
+
186
+ features: {
187
+ settings: true,
188
+ footer: true,
189
+ autoInit: true,
190
+ },
191
+
192
+ templateMapping: {
193
+ "row-key": null,
194
+ "filter-id": null,
195
+ },
196
+ },
197
+ initOptionsFromArguments.call(this),
198
+ );
199
+ }
200
+
201
+ /**
202
+ *
203
+ * @param {string} selector
204
+ * @returns {NodeListOf<*>}
205
+ */
206
+ getGridElements(selector) {
207
+ return this[gridElementSymbol].querySelectorAll(selector);
208
+ }
209
+
210
+ /**
211
+ *
212
+ * @return {string}
213
+ */
214
+ static getTag() {
215
+ return "monster-datatable";
216
+ }
217
+
218
+ /**
219
+ *
220
+ * @return {Monster.Components.Form.Form}
221
+ */
222
+ [assembleMethodSymbol]() {
223
+ const rawKey = this.getOption("templateMapping.row-key");
224
+
225
+ if (rawKey === null) {
226
+ if (this.id !== null && this.id !== "") {
227
+ const rawKey = this.getOption("templateMapping.row-key");
228
+ if (rawKey === null) {
229
+ this.setOption("templateMapping.row-key", this.id + "-row");
230
+ }
231
+ } else {
232
+ this.setOption("templateMapping.row-key", "row");
233
+ }
234
+ }
235
+
236
+ if (this.id !== null && this.id !== "") {
237
+ this.setOption("templateMapping.filter-id", "" + this.id + "-filter");
238
+ } else {
239
+ this.setOption("templateMapping.filter-id", "filter");
240
+ }
241
+
242
+ super[assembleMethodSymbol]();
243
+
244
+ initControlReferences.call(this);
245
+ initEventHandler.call(this);
246
+
247
+ const selector = this.getOption("datasource.selector");
248
+
249
+ if (isString(selector)) {
250
+ const elements = document.querySelectorAll(selector);
251
+ if (elements.length !== 1) {
252
+ throw new Error("the selector must match exactly one element");
253
+ }
254
+
255
+ const element = elements[0];
256
+
257
+ if (!isInstance(element, Datasource)) {
258
+ throw new TypeError("the element must be a datasource");
259
+ }
260
+
261
+ this[datasourceLinkedElementSymbol] = element;
262
+
263
+ setTimeout(() => {
264
+ handleDataSourceChanges.call(this);
265
+ element.datasource.attachObserver(
266
+ new Observer(handleDataSourceChanges.bind(this)),
267
+ );
268
+ }, 0);
269
+ }
270
+
271
+ getHostConfig
272
+ .call(this, getColumnVisibilityConfigKey)
273
+ .then((config) => {
274
+ const headerOrderMap = new Map();
275
+
276
+ getHostConfig
277
+ .call(this, getStoredOrderConfigKey)
278
+ .then((orderConfig) => {
279
+ if (isArray(orderConfig) || orderConfig.length > 0) {
280
+ for (let i = 0; i < orderConfig.length; i++) {
281
+ const item = orderConfig[i];
282
+ const parts = item.split(" ");
283
+ const field = parts[0];
284
+ const direction = parts[1] || DIRECTION_ASC;
285
+ headerOrderMap.set(field, direction);
286
+ }
287
+ }
288
+ })
289
+ .then(() => {
290
+ try {
291
+ initGridAndStructs.call(this, config, headerOrderMap);
292
+ } catch (error) {
293
+ addAttributeToken(
294
+ this,
295
+ ATTRIBUTE_ERRORMESSAGE,
296
+ error?.message || error.toString(),
297
+ );
298
+ }
299
+
300
+ updateColumnBar.call(this);
301
+ })
302
+ .catch((error) => {
303
+ addAttributeToken(
304
+ this,
305
+ ATTRIBUTE_ERRORMESSAGE,
306
+ error?.message || error.toString(),
307
+ );
308
+ });
309
+ })
310
+ .catch((error) => {
311
+ addAttributeToken(
312
+ this,
313
+ ATTRIBUTE_ERRORMESSAGE,
314
+ error?.message || error.toString(),
315
+ );
316
+ });
317
+ }
318
+
319
+ /**
320
+ *
321
+ * @return {CSSStyleSheet[]}
322
+ */
323
+ static getCSSStyleSheet() {
324
+ return [DatatableStyleSheet];
325
+ }
326
326
  }
327
327
 
328
328
  /**
@@ -330,7 +330,7 @@ class DataTable extends CustomElement {
330
330
  * @returns {string}
331
331
  */
332
332
  function getColumnVisibilityConfigKey() {
333
- return generateUniqueConfigKey("datatable", this?.id, "columns-visibility");
333
+ return generateUniqueConfigKey("datatable", this?.id, "columns-visibility");
334
334
  }
335
335
 
336
336
  /**
@@ -338,7 +338,7 @@ function getColumnVisibilityConfigKey() {
338
338
  * @returns {string}
339
339
  */
340
340
  function getFilterConfigKey() {
341
- return generateUniqueConfigKey("datatable", this?.id, "filter");
341
+ return generateUniqueConfigKey("datatable", this?.id, "filter");
342
342
  }
343
343
 
344
344
  /**
@@ -346,292 +346,293 @@ function getFilterConfigKey() {
346
346
  * @returns {Promise}
347
347
  */
348
348
  function getHostConfig(callback) {
349
- const document = getDocument();
350
- const host = document.querySelector("monster-host");
351
-
352
- if (!(host && this.id)) {
353
- return Promise.resolve({});
354
- }
355
-
356
- if (!host || !isFunction(host?.getConfig)) {
357
- throw new TypeError("the host must be a monster-host");
358
- }
359
-
360
- const configKey = callback.call(this);
361
- return host.hasConfig(configKey).then((hasConfig) => {
362
- if (hasConfig) {
363
- return host.getConfig(configKey);
364
- } else {
365
- return {};
366
- }
367
- });
349
+ const document = getDocument();
350
+ const host = document.querySelector("monster-host");
351
+
352
+ if (!(host && this.id)) {
353
+ return Promise.resolve({});
354
+ }
355
+
356
+ if (!host || !isFunction(host?.getConfig)) {
357
+ throw new TypeError("the host must be a monster-host");
358
+ }
359
+
360
+ const configKey = callback.call(this);
361
+ return host.hasConfig(configKey).then((hasConfig) => {
362
+ if (hasConfig) {
363
+ return host.getConfig(configKey);
364
+ } else {
365
+ return {};
366
+ }
367
+ });
368
368
  }
369
369
 
370
370
  /**
371
371
  * @private
372
372
  */
373
373
  function updateColumnBar() {
374
- if (!this[columnBarElementSymbol]) {
375
- return;
376
- }
377
-
378
- const columns = [];
379
- for (const header of this.getOption("headers")) {
380
- const mode = header.getInternal("mode");
381
-
382
- if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
383
- continue;
384
- }
385
-
386
- columns.push({
387
- visible: mode !== ATTRIBUTE_DATATABLE_MODE_HIDDEN,
388
- name: header.label,
389
- index: header.index,
390
- });
391
- }
392
-
393
- this[columnBarElementSymbol].setOption("columns", columns);
374
+ if (!this[columnBarElementSymbol]) {
375
+ return;
376
+ }
377
+
378
+ const columns = [];
379
+ for (const header of this.getOption("headers")) {
380
+ const mode = header.getInternal("mode");
381
+
382
+ if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
383
+ continue;
384
+ }
385
+
386
+ columns.push({
387
+ visible: mode !== ATTRIBUTE_DATATABLE_MODE_HIDDEN,
388
+ name: header.label,
389
+ index: header.index,
390
+ });
391
+ }
392
+
393
+ this[columnBarElementSymbol].setOption("columns", columns);
394
394
  }
395
395
 
396
396
  /**
397
397
  * @private
398
398
  */
399
399
  function updateHeaderFromColumnBar() {
400
- if (!this[columnBarElementSymbol]) {
401
- return;
402
- }
400
+ if (!this[columnBarElementSymbol]) {
401
+ return;
402
+ }
403
403
 
404
- const options = this[columnBarElementSymbol].getOption("columns");
405
- if (!isArray(options)) return;
404
+ const options = this[columnBarElementSymbol].getOption("columns");
405
+ if (!isArray(options)) return;
406
406
 
407
- const invisibleMap = {};
407
+ const invisibleMap = {};
408
408
 
409
- for (let i = 0; i < options.length; i++) {
410
- const option = options[i];
411
- invisibleMap[option.index] = option.visible;
412
- }
409
+ for (let i = 0; i < options.length; i++) {
410
+ const option = options[i];
411
+ invisibleMap[option.index] = option.visible;
412
+ }
413
413
 
414
- for (const header of this.getOption("headers")) {
415
- const mode = header.getInternal("mode");
414
+ for (const header of this.getOption("headers")) {
415
+ const mode = header.getInternal("mode");
416
416
 
417
- if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
418
- continue;
419
- }
417
+ if (mode === ATTRIBUTE_DATATABLE_MODE_FIXED) {
418
+ continue;
419
+ }
420
420
 
421
- if (invisibleMap[header.index] === false) {
422
- header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_HIDDEN);
423
- } else {
424
- header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_VISIBLE);
425
- }
426
- }
421
+ if (invisibleMap[header.index] === false) {
422
+ header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_HIDDEN);
423
+ } else {
424
+ header.setInternal("mode", ATTRIBUTE_DATATABLE_MODE_VISIBLE);
425
+ }
426
+ }
427
427
  }
428
428
 
429
429
  /**
430
430
  * @private
431
431
  */
432
432
  function updateConfigColumnBar() {
433
- if (!this[columnBarElementSymbol]) {
434
- return;
435
- }
436
-
437
- const options = this[columnBarElementSymbol].getOption("columns");
438
- if (!isArray(options)) return;
439
-
440
- const map = {};
441
- for (let i = 0; i < options.length; i++) {
442
- const option = options[i];
443
- map[option.name] = option.visible;
444
- }
445
-
446
- const document = getDocument();
447
- const host = document.querySelector("monster-host");
448
- if (!(host && this.id)) {
449
- return;
450
- }
451
- const configKey = getColumnVisibilityConfigKey.call(this);
452
-
453
- try {
454
- host.setConfig(configKey, map);
455
- } catch (error) {
456
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
457
- }
433
+ if (!this[columnBarElementSymbol]) {
434
+ return;
435
+ }
436
+
437
+ const options = this[columnBarElementSymbol].getOption("columns");
438
+ if (!isArray(options)) return;
439
+
440
+ const map = {};
441
+ for (let i = 0; i < options.length; i++) {
442
+ const option = options[i];
443
+ map[option.name] = option.visible;
444
+ }
445
+
446
+ const document = getDocument();
447
+ const host = document.querySelector("monster-host");
448
+ if (!(host && this.id)) {
449
+ return;
450
+ }
451
+ const configKey = getColumnVisibilityConfigKey.call(this);
452
+
453
+ try {
454
+ host.setConfig(configKey, map);
455
+ } catch (error) {
456
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
457
+ }
458
458
  }
459
459
 
460
460
  /**
461
461
  * @private
462
462
  */
463
463
  function initEventHandler() {
464
- const self = this;
465
-
466
- getWindow().addEventListener("resize", (event) => {
467
- updateGrid.call(self);
468
- });
469
-
470
- self[columnBarElementSymbol].attachObserver(
471
- new Observer((e) => {
472
- updateHeaderFromColumnBar.call(self);
473
- updateGrid.call(self);
474
- updateConfigColumnBar.call(self);
475
- }),
476
- );
477
-
478
- self[gridHeadersElementSymbol].addEventListener("click", function (event) {
479
- let element = null;
480
- const datasource = self[datasourceLinkedElementSymbol];
481
- if (!datasource) {
482
- return;
483
- }
484
-
485
- element = findTargetElementFromEvent(event, ATTRIBUTE_DATATABLE_SORTABLE);
486
- if (element) {
487
- const index = element.parentNode.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
488
- const headers = self.getOption("headers");
489
-
490
- event.preventDefault();
491
-
492
- headers[index].changeDirection();
493
-
494
- setTimeout(function () {
495
- /** hotfix, normally this should be done via the updater, no idea why this is not possible. */
496
- element.setAttribute(
497
- ATTRIBUTE_DATATABLE_SORTABLE,
498
- `${headers[index].field} ${headers[index].direction}`,
499
- );
500
-
501
- storeOrderStatement.call(self, true);
502
- }, 0);
503
- }
504
- });
464
+ const self = this;
465
+
466
+ getWindow().addEventListener("resize", (event) => {
467
+ updateGrid.call(self);
468
+ });
469
+
470
+ self[columnBarElementSymbol].attachObserver(
471
+ new Observer((e) => {
472
+ updateHeaderFromColumnBar.call(self);
473
+ updateGrid.call(self);
474
+ updateConfigColumnBar.call(self);
475
+ }),
476
+ );
477
+
478
+ self[gridHeadersElementSymbol].addEventListener("click", function (event) {
479
+ let element = null;
480
+ const datasource = self[datasourceLinkedElementSymbol];
481
+ if (!datasource) {
482
+ return;
483
+ }
484
+
485
+ element = findTargetElementFromEvent(event, ATTRIBUTE_DATATABLE_SORTABLE);
486
+ if (element) {
487
+ const index = element.parentNode.getAttribute(ATTRIBUTE_DATATABLE_INDEX);
488
+ const headers = self.getOption("headers");
489
+
490
+ event.preventDefault();
491
+
492
+ headers[index].changeDirection();
493
+
494
+ setTimeout(function () {
495
+ /** hotfix, normally this should be done via the updater, no idea why this is not possible. */
496
+ element.setAttribute(
497
+ ATTRIBUTE_DATATABLE_SORTABLE,
498
+ `${headers[index].field} ${headers[index].direction}`,
499
+ );
500
+
501
+ storeOrderStatement.call(self, true);
502
+ }, 0);
503
+ }
504
+ });
505
505
  }
506
506
 
507
507
  /**
508
508
  * @private
509
509
  */
510
510
  function initGridAndStructs(hostConfig, headerOrderMap) {
511
- const rowID = this.getOption("templateMapping.row-key");
512
-
513
- if (!this[gridElementSymbol]) {
514
- throw new Error("no grid element is defined");
515
- }
516
-
517
- let template;
518
- getSlottedElements.call(this).forEach((e) => {
519
- if (e instanceof HTMLTemplateElement && e.id === rowID) {
520
- template = e;
521
- }
522
- });
523
-
524
- if (!template) {
525
- throw new Error("no template is defined");
526
- }
527
-
528
- const rowCount = template.content.children.length;
529
-
530
- const headers = [];
531
-
532
- for (let i = 0; i < rowCount; i++) {
533
- let hClass = "";
534
- const row = template.content.children[i];
535
-
536
- let mode = "";
537
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_MODE)) {
538
- mode = row.getAttribute(ATTRIBUTE_DATATABLE_MODE);
539
- }
540
-
541
- let grid = row.getAttribute(ATTRIBUTE_DATATABLE_GRID_TEMPLATE);
542
- if (!grid || grid === "" || grid === "auto") {
543
- grid = "minmax(0, 1fr)";
544
- }
545
-
546
- let label = "";
547
- let labelKey = "";
548
-
549
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_HEAD)) {
550
- label = row.getAttribute(ATTRIBUTE_DATATABLE_HEAD);
551
- labelKey = label;
552
-
553
- try {
554
- if (label.startsWith("i18n:")) {
555
- label = label.substring(5, label.length);
556
- label = getDocumentTranslations().getText(label, label);
557
- }
558
- } catch (e) {
559
- label = "i18n error " + label;
560
- }
561
- }
562
-
563
- if (!label) {
564
- label = i + 1 + "";
565
- mode = ATTRIBUTE_DATATABLE_MODE_FIXED;
566
- labelKey = label;
567
- }
568
-
569
- if (isObject(hostConfig) && hostConfig.hasOwnProperty(label)) {
570
- if (hostConfig[label] === false) {
571
- mode = ATTRIBUTE_DATATABLE_MODE_HIDDEN;
572
- } else {
573
- mode = ATTRIBUTE_DATATABLE_MODE_VISIBLE;
574
- }
575
- }
576
-
577
- let align = "";
578
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_ALIGN)) {
579
- align = row.getAttribute(ATTRIBUTE_DATATABLE_ALIGN);
580
- }
581
-
582
- switch (align) {
583
- case "center":
584
- hClass = "flex-center";
585
- break;
586
- case "end":
587
- hClass = "flex-end";
588
- break;
589
- case "start":
590
- hClass = "flex-start";
591
- break;
592
- default:
593
- hClass = "flex-start";
594
- }
595
-
596
- let field = "";
597
- let direction = DIRECTION_NONE;
598
- if (row.hasAttribute(ATTRIBUTE_DATATABLE_SORTABLE)) {
599
- field = row.getAttribute(ATTRIBUTE_DATATABLE_SORTABLE).trim();
600
- const parts = field.split(" ").map((item) => item.trim());
601
- field = parts[0];
602
-
603
- if (headerOrderMap.has(field)) {
604
- direction = headerOrderMap.get(field);
605
- } else if (parts.length === 2 && [DIRECTION_ASC, DIRECTION_DESC].indexOf(parts[1]) !== -1) {
606
- direction = parts[1];
607
- }
608
- }
609
-
610
- if (mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
611
- hClass += " hidden";
612
- }
613
-
614
- const header = new Header();
615
- header.setInternals({
616
- field: field,
617
- label: label,
618
- classes: hClass,
619
- index: i,
620
- mode: mode,
621
- grid: grid,
622
- labelKey: labelKey,
623
- direction: direction,
624
- });
625
-
626
- headers.push(header);
627
- }
628
-
629
- this.setOption("headers", headers);
630
- setTimeout(() => {
631
- storeOrderStatement.call(this, this.getOption("features.autoInit"));
632
-
633
- },
634
- 0);
511
+ const rowID = this.getOption("templateMapping.row-key");
512
+
513
+ if (!this[gridElementSymbol]) {
514
+ throw new Error("no grid element is defined");
515
+ }
516
+
517
+ let template;
518
+ getSlottedElements.call(this).forEach((e) => {
519
+ if (e instanceof HTMLTemplateElement && e.id === rowID) {
520
+ template = e;
521
+ }
522
+ });
523
+
524
+ if (!template) {
525
+ throw new Error("no template is defined");
526
+ }
527
+
528
+ const rowCount = template.content.children.length;
529
+
530
+ const headers = [];
531
+
532
+ for (let i = 0; i < rowCount; i++) {
533
+ let hClass = "";
534
+ const row = template.content.children[i];
535
+
536
+ let mode = "";
537
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_MODE)) {
538
+ mode = row.getAttribute(ATTRIBUTE_DATATABLE_MODE);
539
+ }
540
+
541
+ let grid = row.getAttribute(ATTRIBUTE_DATATABLE_GRID_TEMPLATE);
542
+ if (!grid || grid === "" || grid === "auto") {
543
+ grid = "minmax(0, 1fr)";
544
+ }
545
+
546
+ let label = "";
547
+ let labelKey = "";
548
+
549
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_HEAD)) {
550
+ label = row.getAttribute(ATTRIBUTE_DATATABLE_HEAD);
551
+ labelKey = label;
552
+
553
+ try {
554
+ if (label.startsWith("i18n:")) {
555
+ label = label.substring(5, label.length);
556
+ label = getDocumentTranslations().getText(label, label);
557
+ }
558
+ } catch (e) {
559
+ label = "i18n error " + label;
560
+ }
561
+ }
562
+
563
+ if (!label) {
564
+ label = i + 1 + "";
565
+ mode = ATTRIBUTE_DATATABLE_MODE_FIXED;
566
+ labelKey = label;
567
+ }
568
+
569
+ if (isObject(hostConfig) && hostConfig.hasOwnProperty(label)) {
570
+ if (hostConfig[label] === false) {
571
+ mode = ATTRIBUTE_DATATABLE_MODE_HIDDEN;
572
+ } else {
573
+ mode = ATTRIBUTE_DATATABLE_MODE_VISIBLE;
574
+ }
575
+ }
576
+
577
+ let align = "";
578
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_ALIGN)) {
579
+ align = row.getAttribute(ATTRIBUTE_DATATABLE_ALIGN);
580
+ }
581
+
582
+ switch (align) {
583
+ case "center":
584
+ hClass = "flex-center";
585
+ break;
586
+ case "end":
587
+ hClass = "flex-end";
588
+ break;
589
+ case "start":
590
+ hClass = "flex-start";
591
+ break;
592
+ default:
593
+ hClass = "flex-start";
594
+ }
595
+
596
+ let field = "";
597
+ let direction = DIRECTION_NONE;
598
+ if (row.hasAttribute(ATTRIBUTE_DATATABLE_SORTABLE)) {
599
+ field = row.getAttribute(ATTRIBUTE_DATATABLE_SORTABLE).trim();
600
+ const parts = field.split(" ").map((item) => item.trim());
601
+ field = parts[0];
602
+
603
+ if (headerOrderMap.has(field)) {
604
+ direction = headerOrderMap.get(field);
605
+ } else if (
606
+ parts.length === 2 &&
607
+ [DIRECTION_ASC, DIRECTION_DESC].indexOf(parts[1]) !== -1
608
+ ) {
609
+ direction = parts[1];
610
+ }
611
+ }
612
+
613
+ if (mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
614
+ hClass += " hidden";
615
+ }
616
+
617
+ const header = new Header();
618
+ header.setInternals({
619
+ field: field,
620
+ label: label,
621
+ classes: hClass,
622
+ index: i,
623
+ mode: mode,
624
+ grid: grid,
625
+ labelKey: labelKey,
626
+ direction: direction,
627
+ });
628
+
629
+ headers.push(header);
630
+ }
631
+
632
+ this.setOption("headers", headers);
633
+ setTimeout(() => {
634
+ storeOrderStatement.call(this, this.getOption("features.autoInit"));
635
+ }, 0);
635
636
  }
636
637
 
637
638
  /**
@@ -639,80 +640,79 @@ function initGridAndStructs(hostConfig, headerOrderMap) {
639
640
  * @returns {string}
640
641
  */
641
642
  export function getStoredOrderConfigKey() {
642
- return generateUniqueConfigKey("datatable", this?.id, "stored-order");
643
+ return generateUniqueConfigKey("datatable", this?.id, "stored-order");
643
644
  }
644
645
 
645
646
  /**
646
647
  * @private
647
648
  */
648
649
  function storeOrderStatement(doFetch) {
649
-
650
- const headers = this.getOption("headers");
651
- const statement = createOrderStatement(headers);
652
- setDataSource.call(this, {orderBy: statement}, doFetch);
653
-
654
- const document = getDocument();
655
- const host = document.querySelector("monster-host");
656
- if (!(host && this.id)) {
657
- return;
658
- }
659
-
660
- const configKey = getStoredOrderConfigKey.call(this);
661
-
662
- // statement explode with , and remove all empty
663
- const list = statement.split(",").filter((item) => item.trim() !== "");
664
- if (list.length === 0) {
665
- // host.deleteConfig(configKey);
666
- return;
667
- }
668
-
669
- host.setConfig(configKey, list);
650
+ const headers = this.getOption("headers");
651
+ const statement = createOrderStatement(headers);
652
+ setDataSource.call(this, { orderBy: statement }, doFetch);
653
+
654
+ const document = getDocument();
655
+ const host = document.querySelector("monster-host");
656
+ if (!(host && this.id)) {
657
+ return;
658
+ }
659
+
660
+ const configKey = getStoredOrderConfigKey.call(this);
661
+
662
+ // statement explode with , and remove all empty
663
+ const list = statement.split(",").filter((item) => item.trim() !== "");
664
+ if (list.length === 0) {
665
+ // host.deleteConfig(configKey);
666
+ return;
667
+ }
668
+
669
+ host.setConfig(configKey, list);
670
670
  }
671
671
 
672
672
  /**
673
673
  * @private
674
674
  */
675
675
  function updateGrid() {
676
- if (!this[gridElementSymbol]) {
677
- throw new Error("no grid element is defined");
678
- }
679
-
680
- let gridTemplateColumns = "";
681
-
682
- const headers = this.getOption("headers");
683
-
684
- let styles = "";
685
-
686
- for (let i = 0; i < headers.length; i++) {
687
- const header = headers[i];
688
-
689
- if (header.mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
690
- styles += `[data-monster-role=datatable]>[data-monster-head="${header.labelKey}"] { display: none; }\n`;
691
- styles += `[data-monster-role=datatable-headers]>[data-monster-index="${header.index}"] { display: none; }\n`;
692
- } else {
693
- gridTemplateColumns += `${header.grid} `;
694
- }
695
- }
696
-
697
- const sheet = new CSSStyleSheet();
698
- if (styles !== "") sheet.replaceSync(styles);
699
- this.shadowRoot.adoptedStyleSheets = [...DataTable.getCSSStyleSheet(), sheet];
700
-
701
- const bodyWidth = getDocument().body.getBoundingClientRect().width;
702
-
703
- const breakpoint = this.getOption("responsive.breakpoint");
704
-
705
- if (bodyWidth > breakpoint) {
706
- this[
707
- gridElementSymbol
708
- ].style.gridTemplateColumns = `${gridTemplateColumns}`;
709
- this[
710
- gridHeadersElementSymbol
711
- ].style.gridTemplateColumns = `${gridTemplateColumns}`;
712
- } else {
713
- this[gridElementSymbol].style.gridTemplateColumns = "auto";
714
- this[gridHeadersElementSymbol].style.gridTemplateColumns = "auto";
715
- }
676
+ if (!this[gridElementSymbol]) {
677
+ throw new Error("no grid element is defined");
678
+ }
679
+
680
+ let gridTemplateColumns = "";
681
+
682
+ const headers = this.getOption("headers");
683
+
684
+ let styles = "";
685
+
686
+ for (let i = 0; i < headers.length; i++) {
687
+ const header = headers[i];
688
+
689
+ if (header.mode === ATTRIBUTE_DATATABLE_MODE_HIDDEN) {
690
+ styles += `[data-monster-role=datatable]>[data-monster-head="${header.labelKey}"] { display: none; }\n`;
691
+ styles += `[data-monster-role=datatable-headers]>[data-monster-index="${header.index}"] { display: none; }\n`;
692
+ } else {
693
+ gridTemplateColumns += `${header.grid} `;
694
+ }
695
+ }
696
+
697
+ const sheet = new CSSStyleSheet();
698
+ if (styles !== "") sheet.replaceSync(styles);
699
+ this.shadowRoot.adoptedStyleSheets = [...DataTable.getCSSStyleSheet(), sheet];
700
+
701
+ const bodyWidth = getDocument().body.getBoundingClientRect().width;
702
+
703
+ const breakpoint = this.getOption("responsive.breakpoint");
704
+
705
+ if (bodyWidth > breakpoint) {
706
+ this[
707
+ gridElementSymbol
708
+ ].style.gridTemplateColumns = `${gridTemplateColumns}`;
709
+ this[
710
+ gridHeadersElementSymbol
711
+ ].style.gridTemplateColumns = `${gridTemplateColumns}`;
712
+ } else {
713
+ this[gridElementSymbol].style.gridTemplateColumns = "auto";
714
+ this[gridHeadersElementSymbol].style.gridTemplateColumns = "auto";
715
+ }
716
716
  }
717
717
 
718
718
  /**
@@ -720,20 +720,20 @@ function updateGrid() {
720
720
  * @param {Monster.Components.Datatable.Header[]} headers
721
721
  * @param {bool} doFetch
722
722
  */
723
- function setDataSource({orderBy}, doFetch) {
724
- const datasource = this[datasourceLinkedElementSymbol];
723
+ function setDataSource({ orderBy }, doFetch) {
724
+ const datasource = this[datasourceLinkedElementSymbol];
725
725
 
726
- if (!datasource) {
727
- return;
728
- }
726
+ if (!datasource) {
727
+ return;
728
+ }
729
729
 
730
- if (isFunction(datasource?.setParameters)) {
731
- datasource.setParameters({orderBy});
732
- }
730
+ if (isFunction(datasource?.setParameters)) {
731
+ datasource.setParameters({ orderBy });
732
+ }
733
733
 
734
- if (doFetch !== false && isFunction(datasource?.fetch)) {
735
- datasource.fetch();
736
- }
734
+ if (doFetch !== false && isFunction(datasource?.fetch)) {
735
+ datasource.fetch();
736
+ }
737
737
  }
738
738
 
739
739
  /**
@@ -741,20 +741,20 @@ function setDataSource({orderBy}, doFetch) {
741
741
  * @return {Monster.Components.Datatable.Form}
742
742
  */
743
743
  function initControlReferences() {
744
- if (!this.shadowRoot) {
745
- throw new Error("no shadow-root is defined");
746
- }
747
-
748
- this[gridElementSymbol] = this.shadowRoot.querySelector(
749
- "[data-monster-role=datatable]",
750
- );
751
- this[gridHeadersElementSymbol] = this.shadowRoot.querySelector(
752
- "[data-monster-role=datatable-headers]",
753
- );
754
- this[columnBarElementSymbol] =
755
- this.shadowRoot.querySelector("monster-column-bar");
756
-
757
- return this;
744
+ if (!this.shadowRoot) {
745
+ throw new Error("no shadow-root is defined");
746
+ }
747
+
748
+ this[gridElementSymbol] = this.shadowRoot.querySelector(
749
+ "[data-monster-role=datatable]",
750
+ );
751
+ this[gridHeadersElementSymbol] = this.shadowRoot.querySelector(
752
+ "[data-monster-role=datatable-headers]",
753
+ );
754
+ this[columnBarElementSymbol] =
755
+ this.shadowRoot.querySelector("monster-column-bar");
756
+
757
+ return this;
758
758
  }
759
759
 
760
760
  /**
@@ -764,22 +764,22 @@ function initControlReferences() {
764
764
  * @throws {Error} the datasource could not be initialized
765
765
  */
766
766
  function initOptionsFromArguments() {
767
- const options = {};
768
- const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
769
-
770
- if (selector) {
771
- options.datasource = {selector: selector};
772
- }
773
-
774
- const breakpoint = this.getAttribute(
775
- ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
776
- );
777
- if (breakpoint) {
778
- options.responsive = {};
779
- options.responsive.breakpoint = parseInt(breakpoint);
780
- }
781
-
782
- return options;
767
+ const options = {};
768
+ const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
769
+
770
+ if (selector) {
771
+ options.datasource = { selector: selector };
772
+ }
773
+
774
+ const breakpoint = this.getAttribute(
775
+ ATTRIBUTE_DATATABLE_RESPONSIVE_BREAKPOINT,
776
+ );
777
+ if (breakpoint) {
778
+ options.responsive = {};
779
+ options.responsive.breakpoint = parseInt(breakpoint);
780
+ }
781
+
782
+ return options;
783
783
  }
784
784
 
785
785
  /**
@@ -787,7 +787,7 @@ function initOptionsFromArguments() {
787
787
  * @return {string}
788
788
  */
789
789
  function getEmptyTemplate() {
790
- return `<monster-state data-monster-role="empty-without-action">
790
+ return `<monster-state data-monster-role="empty-without-action">
791
791
  <div part="visual">
792
792
  <svg width="4rem" height="4rem" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
793
793
  <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"/>
@@ -805,8 +805,8 @@ function getEmptyTemplate() {
805
805
  * @return {string}
806
806
  */
807
807
  function getTemplate() {
808
- // language=HTML
809
- return `
808
+ // language=HTML
809
+ return `
810
810
  <div data-monster-role="control" part="control">
811
811
  <template id="headers-row">
812
812
  <div data-monster-attributes="class path:headers-row.classname,