@schukai/monster 4.83.0 → 4.84.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 +11 -0
- package/package.json +1 -1
- package/source/components/datatable/datatable.mjs +12 -1
- package/source/components/datatable/status.mjs +15 -21
- package/source/components/form/message-state-button.mjs +24 -1
- package/source/dom/customelement.mjs +34 -1
- package/test/cases/components/form/message-state-button.mjs +134 -0
- package/test/web/import.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
## [4.84.0] - 2026-01-08
|
|
6
|
+
|
|
7
|
+
### Add Features
|
|
8
|
+
|
|
9
|
+
- Add initial implementation for issue [#366](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/366) and [#367](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/367) with accompanying HTML and MJS files
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
- Enhance message-state-button synchronization for disabled state
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
5
16
|
## [4.83.0] - 2026-01-07
|
|
6
17
|
|
|
7
18
|
### Add Features
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.
|
|
1
|
+
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.84.0"}
|
|
@@ -122,6 +122,11 @@ const copyAllElementSymbol = Symbol("copyAllElement");
|
|
|
122
122
|
* @type {symbol}
|
|
123
123
|
*/
|
|
124
124
|
const resizeObserverSymbol = Symbol("resizeObserver");
|
|
125
|
+
/**
|
|
126
|
+
* @private
|
|
127
|
+
* @type {symbol}
|
|
128
|
+
*/
|
|
129
|
+
const suppressColumnConfigSaveSymbol = Symbol("suppressColumnConfigSave");
|
|
125
130
|
|
|
126
131
|
/**
|
|
127
132
|
* A DataTable
|
|
@@ -696,7 +701,11 @@ function updateColumnBar() {
|
|
|
696
701
|
});
|
|
697
702
|
}
|
|
698
703
|
|
|
704
|
+
this[suppressColumnConfigSaveSymbol] = true;
|
|
699
705
|
this[columnBarElementSymbol].setOption("columns", columns);
|
|
706
|
+
queueMicrotask(() => {
|
|
707
|
+
this[suppressColumnConfigSaveSymbol] = false;
|
|
708
|
+
});
|
|
700
709
|
}
|
|
701
710
|
|
|
702
711
|
/**
|
|
@@ -870,7 +879,9 @@ function initEventHandler() {
|
|
|
870
879
|
new Observer(() => {
|
|
871
880
|
updateHeaderFromColumnBar.call(self);
|
|
872
881
|
updateGrid.call(self);
|
|
873
|
-
|
|
882
|
+
if (!self[suppressColumnConfigSaveSymbol]) {
|
|
883
|
+
updateConfigColumnBar.call(self);
|
|
884
|
+
}
|
|
874
885
|
}),
|
|
875
886
|
);
|
|
876
887
|
}
|
|
@@ -45,6 +45,7 @@ const errorElementSymbol = Symbol.for("errorElement");
|
|
|
45
45
|
* @type {symbol}
|
|
46
46
|
*/
|
|
47
47
|
const datasourceLinkedElementSymbol = Symbol("datasourceLinkedElement");
|
|
48
|
+
const spinnerElementSymbol = Symbol("spinnerElement");
|
|
48
49
|
|
|
49
50
|
/**
|
|
50
51
|
* A simple dataset status component
|
|
@@ -164,6 +165,7 @@ function initControlReferences() {
|
|
|
164
165
|
this[errorElementSymbol] = this.shadowRoot.querySelector(
|
|
165
166
|
"monster-context-error",
|
|
166
167
|
);
|
|
168
|
+
this[spinnerElementSymbol] = this.shadowRoot.querySelector(".monster-spinner");
|
|
167
169
|
}
|
|
168
170
|
|
|
169
171
|
/**
|
|
@@ -183,9 +185,18 @@ function initEventHandler() {
|
|
|
183
185
|
throw new TypeError("the element must be a datasource");
|
|
184
186
|
}
|
|
185
187
|
|
|
186
|
-
|
|
188
|
+
const setSpinnerState = (state) => {
|
|
189
|
+
self.setOption("state.spinner", state);
|
|
190
|
+
const spinner = self[spinnerElementSymbol];
|
|
191
|
+
if (spinner) {
|
|
192
|
+
spinner.setAttribute("data-monster-state-loader", state);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
187
195
|
const hideSpinner = () => {
|
|
188
|
-
|
|
196
|
+
setSpinnerState("hide");
|
|
197
|
+
};
|
|
198
|
+
const showSpinner = () => {
|
|
199
|
+
setSpinnerState("show");
|
|
189
200
|
};
|
|
190
201
|
|
|
191
202
|
this[datasourceLinkedElementSymbol] = element;
|
|
@@ -194,35 +205,18 @@ function initEventHandler() {
|
|
|
194
205
|
if (typeof self[errorElementSymbol]?.resetErrorMessage === "function") {
|
|
195
206
|
self[errorElementSymbol].resetErrorMessage();
|
|
196
207
|
}
|
|
197
|
-
|
|
198
|
-
clearTimeout(fadeOutTimer);
|
|
199
|
-
fadeOutTimer = null;
|
|
200
|
-
}
|
|
201
|
-
fadeOutTimer = setTimeout(() => {
|
|
202
|
-
fadeOutTimer = null;
|
|
203
|
-
hideSpinner();
|
|
204
|
-
}, 800);
|
|
208
|
+
hideSpinner();
|
|
205
209
|
});
|
|
206
210
|
|
|
207
211
|
element.addEventListener("monster-datasource-fetch", function () {
|
|
208
|
-
if (fadeOutTimer) {
|
|
209
|
-
clearTimeout(fadeOutTimer);
|
|
210
|
-
fadeOutTimer = null;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
212
|
if (typeof self[errorElementSymbol]?.resetErrorMessage === "function") {
|
|
214
213
|
self[errorElementSymbol].resetErrorMessage();
|
|
215
214
|
}
|
|
216
215
|
|
|
217
|
-
|
|
216
|
+
showSpinner();
|
|
218
217
|
});
|
|
219
218
|
|
|
220
219
|
element.addEventListener("monster-datasource-error", function (event) {
|
|
221
|
-
if (fadeOutTimer) {
|
|
222
|
-
clearTimeout(fadeOutTimer);
|
|
223
|
-
fadeOutTimer = null;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
220
|
hideSpinner();
|
|
227
221
|
|
|
228
222
|
const timeout = self.getOption("timeouts.message", 4000);
|
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { instanceSymbol } from "../../constants.mjs";
|
|
16
|
-
import { ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
|
|
16
|
+
import { ATTRIBUTE_DISABLED, ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
|
|
17
17
|
import {
|
|
18
18
|
assembleMethodSymbol,
|
|
19
|
+
attributeObserverSymbol,
|
|
19
20
|
registerCustomElement,
|
|
20
21
|
} from "../../dom/customelement.mjs";
|
|
21
22
|
import { isArray, isString } from "../../types/is.mjs";
|
|
@@ -411,9 +412,31 @@ function initDisabledSync() {
|
|
|
411
412
|
if (self.getOption("features.disableButton", false) !== disabled) {
|
|
412
413
|
self.setOption("features.disableButton", disabled);
|
|
413
414
|
}
|
|
415
|
+
|
|
416
|
+
const button = self[buttonElementSymbol];
|
|
417
|
+
if (!button) {
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (disabled) {
|
|
422
|
+
button.setAttribute(ATTRIBUTE_DISABLED, "");
|
|
423
|
+
} else {
|
|
424
|
+
button.removeAttribute(ATTRIBUTE_DISABLED);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (isFunction(button.setOption)) {
|
|
428
|
+
button.setOption("disabled", disabled);
|
|
429
|
+
}
|
|
414
430
|
};
|
|
415
431
|
|
|
416
432
|
syncDisabled();
|
|
433
|
+
const existingObserver = self[attributeObserverSymbol]?.[ATTRIBUTE_DISABLED];
|
|
434
|
+
if (existingObserver) {
|
|
435
|
+
self[attributeObserverSymbol][ATTRIBUTE_DISABLED] = () => {
|
|
436
|
+
existingObserver.call(self);
|
|
437
|
+
syncDisabled();
|
|
438
|
+
};
|
|
439
|
+
}
|
|
417
440
|
self.attachObserver(new Observer(syncDisabled));
|
|
418
441
|
}
|
|
419
442
|
|
|
@@ -1039,7 +1039,7 @@ function initOptionObserver() {
|
|
|
1039
1039
|
for (const list of updaters) {
|
|
1040
1040
|
for (const updater of list) {
|
|
1041
1041
|
const d = clone(self[internalSymbol].getRealSubject()["options"]);
|
|
1042
|
-
|
|
1042
|
+
syncUpdaterSubject(updater.getSubject(), d);
|
|
1043
1043
|
}
|
|
1044
1044
|
}
|
|
1045
1045
|
}),
|
|
@@ -1068,6 +1068,39 @@ function initOptionObserver() {
|
|
|
1068
1068
|
};
|
|
1069
1069
|
}
|
|
1070
1070
|
|
|
1071
|
+
/**
|
|
1072
|
+
* @private
|
|
1073
|
+
* @param {object} target
|
|
1074
|
+
* @param {object} source
|
|
1075
|
+
* @return {void}
|
|
1076
|
+
*/
|
|
1077
|
+
function syncUpdaterSubject(target, source) {
|
|
1078
|
+
if (!isObject(source)) {
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
for (const [key, value] of Object.entries(source)) {
|
|
1083
|
+
if (isArray(value)) {
|
|
1084
|
+
if (!isArray(target?.[key])) {
|
|
1085
|
+
target[key] = [];
|
|
1086
|
+
}
|
|
1087
|
+
target[key].length = 0;
|
|
1088
|
+
target[key].push(...clone(value));
|
|
1089
|
+
continue;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
if (isObject(value)) {
|
|
1093
|
+
if (!isObject(target?.[key]) || isArray(target?.[key])) {
|
|
1094
|
+
target[key] = {};
|
|
1095
|
+
}
|
|
1096
|
+
syncUpdaterSubject(target[key], value);
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
target[key] = value;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1071
1104
|
/**
|
|
1072
1105
|
* @private
|
|
1073
1106
|
* @return {object}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { getGlobal } from "../../../../source/types/global.mjs";
|
|
2
|
+
import * as chai from "chai";
|
|
3
|
+
import { chaiDom } from "../../../util/chai-dom.mjs";
|
|
4
|
+
import { initJSDOM } from "../../../util/jsdom.mjs";
|
|
5
|
+
import { ResizeObserverMock } from "../../../util/resize-observer.mjs";
|
|
6
|
+
|
|
7
|
+
let expect = chai.expect;
|
|
8
|
+
chai.use(chaiDom);
|
|
9
|
+
|
|
10
|
+
const global = getGlobal();
|
|
11
|
+
|
|
12
|
+
let html1 = `
|
|
13
|
+
<div id="test1">
|
|
14
|
+
</div>
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
let html2 = `
|
|
18
|
+
<div id="test2">
|
|
19
|
+
<monster-message-state-button data-monster-option-labels-button="Save">
|
|
20
|
+
Save
|
|
21
|
+
</monster-message-state-button>
|
|
22
|
+
</div>
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
let MessageStateButton;
|
|
26
|
+
|
|
27
|
+
describe("MessageStateButton", function () {
|
|
28
|
+
before(function (done) {
|
|
29
|
+
initJSDOM().then(() => {
|
|
30
|
+
import("element-internals-polyfill").catch((e) => done(e));
|
|
31
|
+
|
|
32
|
+
if (!global.ResizeObserver) {
|
|
33
|
+
global.ResizeObserver = ResizeObserverMock;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
import("../../../../source/components/form/message-state-button.mjs")
|
|
37
|
+
.then((m) => {
|
|
38
|
+
MessageStateButton = m["MessageStateButton"];
|
|
39
|
+
done();
|
|
40
|
+
})
|
|
41
|
+
.catch((e) => done(e));
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe("new MessageStateButton", function () {
|
|
46
|
+
beforeEach(() => {
|
|
47
|
+
let mocks = document.getElementById("mocks");
|
|
48
|
+
mocks.innerHTML = html1;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
let mocks = document.getElementById("mocks");
|
|
53
|
+
mocks.innerHTML = "";
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("create from template", function () {
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
let mocks = document.getElementById("mocks");
|
|
59
|
+
mocks.innerHTML = html2;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
let mocks = document.getElementById("mocks");
|
|
64
|
+
mocks.innerHTML = "";
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("should contain monster-message-state-button", function () {
|
|
68
|
+
expect(document.getElementById("test2")).contain.html(
|
|
69
|
+
"<monster-message-state-button",
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("document.createElement", function () {
|
|
75
|
+
it("should instance of message-state-button", function () {
|
|
76
|
+
expect(document.createElement("monster-message-state-button")).is
|
|
77
|
+
.instanceof(MessageStateButton);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("disabled toggle", function () {
|
|
83
|
+
afterEach(() => {
|
|
84
|
+
let mocks = document.getElementById("mocks");
|
|
85
|
+
mocks.innerHTML = "";
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("should sync disabled attribute to inner button", function (done) {
|
|
89
|
+
let mocks = document.getElementById("mocks");
|
|
90
|
+
const button = document.createElement("monster-message-state-button");
|
|
91
|
+
button.innerHTML = "Save";
|
|
92
|
+
mocks.appendChild(button);
|
|
93
|
+
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
try {
|
|
96
|
+
const inner = button.shadowRoot.querySelector(
|
|
97
|
+
"monster-state-button",
|
|
98
|
+
);
|
|
99
|
+
expect(inner).to.exist;
|
|
100
|
+
|
|
101
|
+
button.setAttribute("disabled", "");
|
|
102
|
+
setTimeout(() => {
|
|
103
|
+
try {
|
|
104
|
+
expect(inner.hasAttribute("disabled")).to.be.true;
|
|
105
|
+
|
|
106
|
+
button.removeAttribute("disabled");
|
|
107
|
+
setTimeout(() => {
|
|
108
|
+
try {
|
|
109
|
+
expect(inner.hasAttribute("disabled")).to.be.false;
|
|
110
|
+
|
|
111
|
+
button.setAttribute("disabled", "");
|
|
112
|
+
setTimeout(() => {
|
|
113
|
+
try {
|
|
114
|
+
expect(inner.hasAttribute("disabled")).to.be.true;
|
|
115
|
+
done();
|
|
116
|
+
} catch (e) {
|
|
117
|
+
done(e);
|
|
118
|
+
}
|
|
119
|
+
}, 0);
|
|
120
|
+
} catch (e) {
|
|
121
|
+
done(e);
|
|
122
|
+
}
|
|
123
|
+
}, 0);
|
|
124
|
+
} catch (e) {
|
|
125
|
+
done(e);
|
|
126
|
+
}
|
|
127
|
+
}, 0);
|
|
128
|
+
} catch (e) {
|
|
129
|
+
done(e);
|
|
130
|
+
}
|
|
131
|
+
}, 0);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
package/test/web/import.js
CHANGED
|
@@ -7,6 +7,7 @@ import "../cases/components/form/buy-box.mjs";
|
|
|
7
7
|
import "../cases/components/form/button-bar.mjs";
|
|
8
8
|
import "../cases/components/form/reload.mjs";
|
|
9
9
|
import "../cases/components/form/state-button.mjs";
|
|
10
|
+
import "../cases/components/form/message-state-button.mjs";
|
|
10
11
|
import "../cases/components/form/select.mjs";
|
|
11
12
|
import "../cases/components/form/confirm-button.mjs";
|
|
12
13
|
import "../cases/components/form/form.mjs";
|