@schukai/monster 4.90.0 → 4.91.1
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 +17 -0
- package/package.json +1 -1
- package/source/components/datatable/save-button.mjs +149 -29
- package/source/components/form/repeat-field-set.mjs +1138 -0
- package/source/components/form/select.mjs +8 -1
- package/source/components/form/style/field-set.pcss +2 -296
- package/source/components/form/style/mixin/field-set-layout.pcss +545 -0
- package/source/components/form/style/repeat-field-set-items.pcss +11 -0
- package/source/components/form/style/repeat-field-set.pcss +45 -0
- package/source/components/form/stylesheet/field-set.mjs +1 -1
- package/source/components/form/stylesheet/mixin/field-set-layout.mjs +38 -0
- package/source/components/form/stylesheet/repeat-field-set-items.mjs +38 -0
- package/source/components/form/stylesheet/repeat-field-set.mjs +38 -0
- package/source/data/diff.mjs +0 -4
- package/source/monster.mjs +1 -0
- package/source/types/version.mjs +1 -1
- package/test/cases/data/diff.mjs +24 -1
- package/test/cases/monster.mjs +1 -1
- package/test/web/import.js +1 -1
- package/test/web/test.html +2 -2
- package/test/web/tests.js +952 -457
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
## [4.91.1] - 2026-01-12
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- update colums
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## [4.91.0] - 2026-01-12
|
|
14
|
+
|
|
15
|
+
### Add Features
|
|
16
|
+
|
|
17
|
+
- Update records and improve diff functionality [#372](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/372)
|
|
18
|
+
- Add new dynamic form element with repeatable fields [#372](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/372)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
5
22
|
## [4.90.0] - 2026-01-11
|
|
6
23
|
|
|
7
24
|
### 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.91.1"}
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
findElementWithSelectorUpwards,
|
|
33
33
|
getDocument,
|
|
34
34
|
} from "../../dom/util.mjs";
|
|
35
|
-
import { isString, isArray } from "../../types/is.mjs";
|
|
35
|
+
import { isString, isArray, isObject } from "../../types/is.mjs";
|
|
36
36
|
import { Observer } from "../../types/observer.mjs";
|
|
37
37
|
import { TokenList } from "../../types/tokenlist.mjs";
|
|
38
38
|
import { clone } from "../../util/clone.mjs";
|
|
@@ -74,6 +74,7 @@ const badgeElementSymbol = Symbol("badgeElement");
|
|
|
74
74
|
const saveInFlightSymbol = Symbol("saveInFlight");
|
|
75
75
|
const pendingResetSymbol = Symbol("pendingReset");
|
|
76
76
|
const fetchInFlightSymbol = Symbol("fetchInFlight");
|
|
77
|
+
const originInitializedSymbol = Symbol("originInitialized");
|
|
77
78
|
|
|
78
79
|
/**
|
|
79
80
|
* A save button component
|
|
@@ -135,7 +136,7 @@ class SaveButton extends CustomElement {
|
|
|
135
136
|
selector: null,
|
|
136
137
|
},
|
|
137
138
|
|
|
138
|
-
changes: "
|
|
139
|
+
changes: "",
|
|
139
140
|
|
|
140
141
|
ignoreChanges: [],
|
|
141
142
|
|
|
@@ -204,13 +205,11 @@ class SaveButton extends CustomElement {
|
|
|
204
205
|
});
|
|
205
206
|
element.addEventListener("monster-datasource-fetched", () => {
|
|
206
207
|
self[fetchInFlightSymbol] = false;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
updateChangesState.call(self);
|
|
213
|
-
}
|
|
208
|
+
setOriginValues.call(
|
|
209
|
+
self,
|
|
210
|
+
clone(self[datasourceLinkedElementSymbol].data),
|
|
211
|
+
);
|
|
212
|
+
updateChangesState.call(self);
|
|
214
213
|
});
|
|
215
214
|
element.addEventListener("monster-datasource-error", () => {
|
|
216
215
|
self[fetchInFlightSymbol] = false;
|
|
@@ -293,6 +292,7 @@ function setOriginValues(value) {
|
|
|
293
292
|
if (datasource) {
|
|
294
293
|
datasource[originValuesSymbol] = value;
|
|
295
294
|
}
|
|
295
|
+
this[originInitializedSymbol] = true;
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
/**
|
|
@@ -304,6 +304,7 @@ function clearOriginValues() {
|
|
|
304
304
|
if (datasource) {
|
|
305
305
|
datasource[originValuesSymbol] = null;
|
|
306
306
|
}
|
|
307
|
+
this[originInitializedSymbol] = false;
|
|
307
308
|
}
|
|
308
309
|
|
|
309
310
|
function getTranslations() {
|
|
@@ -374,19 +375,9 @@ function initControlReferences() {
|
|
|
374
375
|
|
|
375
376
|
if (this[stateButtonElementSymbol]) {
|
|
376
377
|
queueMicrotask(() => {
|
|
377
|
-
|
|
378
|
-
changed: new State(
|
|
379
|
-
"changed",
|
|
380
|
-
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cloud-arrow-up" viewBox="0 0 16 16">' +
|
|
381
|
-
'<path fill-rule="evenodd" d="M7.646 5.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 6.707V10.5a.5.5 0 0 1-1 0V6.707L6.354 7.854a.5.5 0 1 1-.708-.708z"/>' +
|
|
382
|
-
'<path d="M4.406 3.342A5.53 5.53 0 0 1 8 2c2.69 0 4.923 2 5.166 4.579C14.758 6.804 16 8.137 16 9.773 16 11.569 14.502 13 12.687 13H3.781C1.708 13 0 11.366 0 9.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383m.653.757c-.757.653-1.153 1.44-1.153 2.056v.448l-.445.049C2.064 6.805 1 7.952 1 9.318 1 10.785 2.23 12 3.781 12h8.906C13.98 12 15 10.988 15 9.773c0-1.216-1.02-2.228-2.313-2.228h-.5v-.5C12.188 4.825 10.328 3 8 3a4.53 4.53 0 0 0-2.941 1.1z"/>' +
|
|
383
|
-
"</svg>",
|
|
384
|
-
),
|
|
385
|
-
};
|
|
386
|
-
|
|
378
|
+
ensureChangedState.call(this);
|
|
387
379
|
this[stateButtonElementSymbol].removeState();
|
|
388
380
|
this[stateButtonElementSymbol].setOption("disabled", "disabled");
|
|
389
|
-
this[stateButtonElementSymbol].setOption("states", states);
|
|
390
381
|
this[stateButtonElementSymbol].setOption(
|
|
391
382
|
"labels.button",
|
|
392
383
|
this.getOption("labels.button"),
|
|
@@ -409,7 +400,8 @@ function initEventHandler() {
|
|
|
409
400
|
this[saveInFlightSymbol] = true;
|
|
410
401
|
this[stateButtonElementSymbol].setOption("disabled", true);
|
|
411
402
|
|
|
412
|
-
flushLinkedForms
|
|
403
|
+
flushLinkedForms
|
|
404
|
+
.call(this)
|
|
413
405
|
.then(() => this[datasourceLinkedElementSymbol].write())
|
|
414
406
|
.then(() => {
|
|
415
407
|
clearOriginValues.call(this);
|
|
@@ -419,7 +411,7 @@ function initEventHandler() {
|
|
|
419
411
|
);
|
|
420
412
|
this[stateButtonElementSymbol].removeState();
|
|
421
413
|
this[stateButtonElementSymbol].setOption("disabled", true);
|
|
422
|
-
this.setOption("changes",
|
|
414
|
+
this.setOption("changes", "");
|
|
423
415
|
this.setOption(
|
|
424
416
|
"classes.badge",
|
|
425
417
|
new TokenList(this.getOption("classes.badge"))
|
|
@@ -518,6 +510,24 @@ function updateChangesState() {
|
|
|
518
510
|
const currentValues = this[datasourceLinkedElementSymbol]?.datasource?.get();
|
|
519
511
|
const ignoreChanges = this.getOption("ignoreChanges");
|
|
520
512
|
const originValues = getOriginValues.call(this);
|
|
513
|
+
|
|
514
|
+
if (
|
|
515
|
+
this[originInitializedSymbol] !== true ||
|
|
516
|
+
this[fetchInFlightSymbol] === true ||
|
|
517
|
+
originValues === null ||
|
|
518
|
+
originValues === undefined ||
|
|
519
|
+
(isObject(originValues) &&
|
|
520
|
+
Object.keys(originValues).length === 0 &&
|
|
521
|
+
isObject(currentValues) &&
|
|
522
|
+
Object.keys(currentValues).length === 0)
|
|
523
|
+
) {
|
|
524
|
+
this.setOption("changes", "");
|
|
525
|
+
this.setOption(
|
|
526
|
+
"classes.badge",
|
|
527
|
+
new TokenList(this.getOption("classes.badge")).add("hidden").toString(),
|
|
528
|
+
);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
521
531
|
let result = diff(originValues, currentValues);
|
|
522
532
|
|
|
523
533
|
if (
|
|
@@ -525,10 +535,7 @@ function updateChangesState() {
|
|
|
525
535
|
location.search.includes("logLevel=debug")
|
|
526
536
|
) {
|
|
527
537
|
console.groupCollapsed("SaveButton");
|
|
528
|
-
console.log(
|
|
529
|
-
"originValues",
|
|
530
|
-
JSON.parse(JSON.stringify(originValues)),
|
|
531
|
-
);
|
|
538
|
+
console.log("originValues", JSON.parse(JSON.stringify(originValues)));
|
|
532
539
|
console.log("currentValues", JSON.parse(JSON.stringify(currentValues)));
|
|
533
540
|
console.log("result of diff", result);
|
|
534
541
|
console.log("ignoreChanges", ignoreChanges);
|
|
@@ -576,10 +583,12 @@ function updateChangesState() {
|
|
|
576
583
|
}
|
|
577
584
|
}
|
|
578
585
|
|
|
579
|
-
|
|
586
|
+
const changeCount = countChanges(result);
|
|
587
|
+
if (changeCount > 0) {
|
|
588
|
+
ensureChangedState.call(this);
|
|
580
589
|
this[stateButtonElementSymbol].setState("changed");
|
|
581
590
|
this[stateButtonElementSymbol].setOption("disabled", false);
|
|
582
|
-
this.setOption("changes",
|
|
591
|
+
this.setOption("changes", changeCount);
|
|
583
592
|
this.setOption(
|
|
584
593
|
"classes.badge",
|
|
585
594
|
new TokenList(this.getOption("classes.badge"))
|
|
@@ -589,7 +598,7 @@ function updateChangesState() {
|
|
|
589
598
|
} else {
|
|
590
599
|
this[stateButtonElementSymbol].removeState();
|
|
591
600
|
this[stateButtonElementSymbol].setOption("disabled", true);
|
|
592
|
-
this.setOption("changes",
|
|
601
|
+
this.setOption("changes", "");
|
|
593
602
|
this.setOption(
|
|
594
603
|
"classes.badge",
|
|
595
604
|
new TokenList(this.getOption("classes.badge")).add("hidden").toString(),
|
|
@@ -597,6 +606,117 @@ function updateChangesState() {
|
|
|
597
606
|
}
|
|
598
607
|
}
|
|
599
608
|
|
|
609
|
+
/**
|
|
610
|
+
* @private
|
|
611
|
+
* @param {Array} changes
|
|
612
|
+
* @return {number}
|
|
613
|
+
*/
|
|
614
|
+
function countChanges(changes) {
|
|
615
|
+
if (!isArray(changes) || changes.length === 0) {
|
|
616
|
+
return 0;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
let total = 0;
|
|
620
|
+
for (const change of changes) {
|
|
621
|
+
if (change?.operator === "add") {
|
|
622
|
+
const nonEmpty = countNonEmptyLeafValues(change?.second?.value);
|
|
623
|
+
total += Math.max(1, nonEmpty);
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
if (change?.operator === "remove") {
|
|
628
|
+
const nonEmpty = countNonEmptyLeafValues(change?.first?.value);
|
|
629
|
+
total += Math.max(1, nonEmpty);
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
total += 1;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
return total;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/**
|
|
640
|
+
* @private
|
|
641
|
+
* @param {*} value
|
|
642
|
+
* @return {number}
|
|
643
|
+
*/
|
|
644
|
+
function countNonEmptyLeafValues(value) {
|
|
645
|
+
if (value === null || value === undefined) {
|
|
646
|
+
return 0;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
if (value instanceof Date) {
|
|
650
|
+
return 1;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
if (typeof value === "string") {
|
|
654
|
+
return value.trim() === "" ? 0 : 1;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
if (typeof value === "number") {
|
|
658
|
+
return Number.isFinite(value) ? 1 : 0;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
if (typeof value === "boolean") {
|
|
662
|
+
return 1;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
if (isArray(value)) {
|
|
666
|
+
if (value.length === 0) {
|
|
667
|
+
return 0;
|
|
668
|
+
}
|
|
669
|
+
return value.reduce((sum, item) => sum + countNonEmptyLeafValues(item), 0);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (isObject(value)) {
|
|
673
|
+
const keys = Object.keys(value);
|
|
674
|
+
if (keys.length === 0) {
|
|
675
|
+
return 0;
|
|
676
|
+
}
|
|
677
|
+
return keys.reduce(
|
|
678
|
+
(sum, key) => sum + countNonEmptyLeafValues(value[key]),
|
|
679
|
+
0,
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
return 1;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* @private
|
|
688
|
+
* @return {void}
|
|
689
|
+
*/
|
|
690
|
+
function ensureChangedState() {
|
|
691
|
+
const stateButton = this[stateButtonElementSymbol];
|
|
692
|
+
if (!stateButton || typeof stateButton.getOption !== "function") {
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (stateButton.getOption("states.changed")) {
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const states = Object.assign({}, stateButton.getOption("states") || {}, {
|
|
701
|
+
changed: getChangedState(),
|
|
702
|
+
});
|
|
703
|
+
stateButton.setOption("states", states);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* @private
|
|
708
|
+
* @return {State}
|
|
709
|
+
*/
|
|
710
|
+
function getChangedState() {
|
|
711
|
+
return new State(
|
|
712
|
+
"changed",
|
|
713
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cloud-arrow-up" viewBox="0 0 16 16">' +
|
|
714
|
+
'<path fill-rule="evenodd" d="M7.646 5.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 6.707V10.5a.5.5 0 0 1-1 0V6.707L6.354 7.854a.5.5 0 1 1-.708-.708z"/>' +
|
|
715
|
+
'<path d="M4.406 3.342A5.53 5.53 0 0 1 8 2c2.69 0 4.923 2 5.166 4.579C14.758 6.804 16 8.137 16 9.773 16 11.569 14.502 13 12.687 13H3.781C1.708 13 0 11.366 0 9.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383m.653.757c-.757.653-1.153 1.44-1.153 2.056v.448l-.445.049C2.064 6.805 1 7.952 1 9.318 1 10.785 2.23 12 3.781 12h8.906C13.98 12 15 10.988 15 9.773c0-1.216-1.02-2.228-2.313-2.228h-.5v-.5C12.188 4.825 10.328 3 8 3a4.53 4.53 0 0 0-2.941 1.1z"/>' +
|
|
716
|
+
"</svg>",
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
|
|
600
720
|
/**
|
|
601
721
|
* @param {Object} options
|
|
602
722
|
* @deprecated 2024-12-31
|