@schukai/monster 4.104.0 → 4.106.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.
@@ -91,6 +91,8 @@ class Form extends DataSet {
91
91
 
92
92
  writeBack: {
93
93
  events: ["keyup", "click", "change", "drop", "touchend", "input"],
94
+ transformer: null,
95
+ callbacks: null,
94
96
  },
95
97
 
96
98
  reportValidity: {
@@ -1326,6 +1326,16 @@ function getButtonLabel(node) {
1326
1326
  label = "";
1327
1327
  }
1328
1328
 
1329
+ if (setLabel === true) {
1330
+ if (label.trim() === "") {
1331
+ label = node.textContent || "";
1332
+ }
1333
+ label = label.replace(/\s+/g, " ").trim();
1334
+ const words = label.split(" ").filter((word) => word !== "");
1335
+ if (words.length > 3) {
1336
+ label = `${words.slice(0, 3).join(" ")}…`;
1337
+ }
1338
+ }
1329
1339
  label = label.trim();
1330
1340
 
1331
1341
  if (label === "") {
@@ -60,6 +60,7 @@ export * from "./components/form/cart-control.mjs";
60
60
  export * from "./components/form/context-hint.mjs";
61
61
  export * from "./components/form/select.mjs";
62
62
  export * from "./components/form/login.mjs";
63
+ export * from "./components/form/credential-button.mjs";
63
64
  export * from "./components/form/confirm-button.mjs";
64
65
  export * from "./components/form/context-info.mjs";
65
66
  export * from "./components/form/context-base.mjs";
@@ -156,7 +156,7 @@ function getMonsterVersion() {
156
156
  }
157
157
 
158
158
  /** don't touch, replaced by make with package.json version */
159
- monsterVersion = new Version("4.94.0");
159
+ monsterVersion = new Version("4.104.0");
160
160
 
161
161
  return monsterVersion;
162
162
  }
@@ -0,0 +1,104 @@
1
+ import * as chai from 'chai';
2
+ import {chaiDom} from "../../../util/chai-dom.mjs";
3
+ import {initJSDOM} from "../../../util/jsdom.mjs";
4
+
5
+ let expect = chai.expect;
6
+ chai.use(chaiDom);
7
+
8
+ let Dataset;
9
+
10
+ function buildDatasource(id, payload) {
11
+ const ds = document.createElement('monster-datasource-dom');
12
+ ds.id = id;
13
+ ds.innerHTML = `<script type="application/json">${JSON.stringify(payload)}</script>`;
14
+ return ds;
15
+ }
16
+
17
+ describe('Dataset writeBack sanitizer', function () {
18
+
19
+ before(async function () {
20
+ await initJSDOM();
21
+ await import("element-internals-polyfill").catch(() => {});
22
+ await import("../../../../source/components/datatable/datasource/dom.mjs");
23
+ const mod = await import("../../../../source/components/datatable/dataset.mjs");
24
+ Dataset = mod['DataSet'];
25
+ });
26
+
27
+ beforeEach(() => {
28
+ const mocks = document.getElementById('mocks');
29
+ mocks.innerHTML = '';
30
+ });
31
+
32
+ afterEach(() => {
33
+ const mocks = document.getElementById('mocks');
34
+ mocks.innerHTML = '';
35
+ });
36
+
37
+ it('sanitizes data before write and avoids side effects', async function () {
38
+ const mocks = document.getElementById('mocks');
39
+ const ds = buildDatasource('ds-sanitize', [{}]);
40
+ mocks.appendChild(ds);
41
+
42
+ const dataset = document.createElement('monster-dataset');
43
+ expect(dataset).is.instanceof(Dataset);
44
+
45
+ dataset.setOption('datasource.selector', '#ds-sanitize');
46
+ dataset.setOption('mapping.data', '');
47
+
48
+ const initial = {name: '', email: 'a@b', tags: []};
49
+ dataset.setOption('data', initial);
50
+
51
+ dataset.setOption('writeBack.transformer', 'call:sanitize');
52
+ dataset.setOption('writeBack.callbacks', {
53
+ sanitize: (obj) => {
54
+ for (const [key, value] of Object.entries(obj)) {
55
+ if (value === '' || value === null || value === undefined) {
56
+ delete obj[key];
57
+ continue;
58
+ }
59
+ if (Array.isArray(value) && value.length === 0) {
60
+ delete obj[key];
61
+ }
62
+ }
63
+ return obj;
64
+ },
65
+ });
66
+
67
+ mocks.appendChild(dataset);
68
+
69
+ await new Promise((resolve) => setTimeout(resolve, 30));
70
+ await dataset.write();
71
+
72
+ expect(ds.data[0]).deep.equal({email: 'a@b'});
73
+
74
+ const internal = dataset.getInternalUpdateCloneData();
75
+ expect(internal.data).deep.equal({name: '', email: 'a@b', tags: []});
76
+ expect(initial).deep.equal({name: '', email: 'a@b', tags: []});
77
+ });
78
+
79
+ it('uses original data when sanitizer returns undefined', async function () {
80
+ const mocks = document.getElementById('mocks');
81
+ const ds = buildDatasource('ds-undefined', [{}]);
82
+ mocks.appendChild(ds);
83
+
84
+ const dataset = document.createElement('monster-dataset');
85
+ dataset.setOption('datasource.selector', '#ds-undefined');
86
+ dataset.setOption('mapping.data', '');
87
+
88
+ const initial = {name: '', email: 'a@b'};
89
+ dataset.setOption('data', initial);
90
+
91
+ dataset.setOption('writeBack.transformer', 'call:noop');
92
+ dataset.setOption('writeBack.callbacks', {
93
+ noop: () => undefined,
94
+ });
95
+
96
+ mocks.appendChild(dataset);
97
+
98
+ await new Promise((resolve) => setTimeout(resolve, 30));
99
+ await dataset.write();
100
+
101
+ expect(ds.data[0]).deep.equal({name: '', email: 'a@b'});
102
+ });
103
+
104
+ });
@@ -92,7 +92,30 @@ describe('Tabs', function () {
92
92
 
93
93
  });
94
94
 
95
+ it('should shorten label from content when no explicit label is provided', function (done) {
96
+
97
+ let mocks = document.getElementById('mocks');
98
+ mocks.innerHTML = html1;
99
+
100
+ setTimeout(() => {
101
+ try {
102
+ const tabs = document.getElementById('mytabs');
103
+ expect(tabs).is.instanceof(Tabs);
104
+
105
+ setTimeout(() => {
106
+ const buttons = tabs.shadowRoot.querySelectorAll('button[part=button]');
107
+ const labelSpan = buttons[2].querySelector('span[data-monster-replace]');
108
+ expect(labelSpan).to.not.equal(null);
109
+ expect(labelSpan.textContent.trim()).to.equal('Das ist tab…');
110
+ done();
111
+ }, 100);
112
+ } catch (e) {
113
+ return done(e);
114
+ }
115
+ }, 0);
116
+ });
117
+
95
118
  });
96
119
 
97
120
 
98
- });
121
+ });
@@ -7,7 +7,7 @@ describe('Monster', function () {
7
7
  let monsterVersion
8
8
 
9
9
  /** don´t touch, replaced by make with package.json version */
10
- monsterVersion = new Version("4.94.0")
10
+ monsterVersion = new Version("4.104.0")
11
11
 
12
12
  let m = getMonsterVersion();
13
13
 
@@ -9,8 +9,8 @@
9
9
  </head>
10
10
  <body>
11
11
  <div id="headline" style="display: flex;align-items: center;justify-content: center;flex-direction: column;">
12
- <h1 style='margin-bottom: 0.1em;'>Monster 4.94.0</h1>
13
- <div id="lastupdate" style='font-size:0.7em'>last update Di 13. Jan 13:09:31 CET 2026</div>
12
+ <h1 style='margin-bottom: 0.1em;'>Monster 4.104.0</h1>
13
+ <div id="lastupdate" style='font-size:0.7em'>last update Mi 21. Jan 21:19:58 CET 2026</div>
14
14
  </div>
15
15
  <div id="mocha-errors"
16
16
  style="color: red;font-weight: bold;display: flex;align-items: center;justify-content: center;flex-direction: column;margin:20px;"></div>