@schukai/monster 4.69.1 → 4.70.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 +19 -0
- package/package.json +1 -1
- package/source/components/datatable/dataset.mjs +1 -2
- package/source/components/datatable/save-button.mjs +103 -80
- package/source/components/datatable/util.mjs +12 -6
- package/source/components/form/select.mjs +116 -22
- package/source/components/layout/slider.mjs +3 -3
- package/source/dom/customelement.mjs +76 -0
- package/source/dom/updater.mjs +4 -0
- package/source/dom/util/set-option-from-attribute.mjs +26 -6
- package/source/types/version.mjs +1 -1
- package/test/cases/monster.mjs +1 -1
- package/test/web/test.html +2 -2
- package/test/web/tests.js +181 -30
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
## [4.70.1] - 2026-01-03
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- timing issues [#359](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/359)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## [4.70.0] - 2026-01-03
|
|
14
|
+
|
|
15
|
+
### Add Features
|
|
16
|
+
|
|
17
|
+
- Add Playwright support through Nix configuration and scripts
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
- Enhance value handling for CustomElements in input control updates [#359](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/359)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
5
24
|
## [4.69.1] - 2026-01-03
|
|
6
25
|
|
|
7
26
|
### Bug Fixes
|
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.70.1"}
|
|
@@ -155,9 +155,8 @@ class DataSet extends CustomElement {
|
|
|
155
155
|
refresh() {
|
|
156
156
|
// makes sure that handleDataSourceChanges is called
|
|
157
157
|
return new Promise((resolve) => {
|
|
158
|
-
this.setOption("data", {});
|
|
159
158
|
queueMicrotask(() => {
|
|
160
|
-
handleDataSourceChanges.call(this);
|
|
159
|
+
handleDataSourceChanges.call(this, true);
|
|
161
160
|
resolve();
|
|
162
161
|
});
|
|
163
162
|
});
|
|
@@ -61,6 +61,7 @@ const originValuesSymbol = Symbol("originValues");
|
|
|
61
61
|
const badgeElementSymbol = Symbol("badgeElement");
|
|
62
62
|
const saveInFlightSymbol = Symbol("saveInFlight");
|
|
63
63
|
const pendingResetSymbol = Symbol("pendingReset");
|
|
64
|
+
const fetchInFlightSymbol = Symbol("fetchInFlight");
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
67
|
* A save button component
|
|
@@ -186,8 +187,21 @@ class SaveButton extends CustomElement {
|
|
|
186
187
|
self[pendingResetSymbol] = true;
|
|
187
188
|
return;
|
|
188
189
|
}
|
|
190
|
+
self[fetchInFlightSymbol] = true;
|
|
189
191
|
self[originValuesSymbol] = null;
|
|
190
192
|
});
|
|
193
|
+
element.addEventListener("monster-datasource-fetched", () => {
|
|
194
|
+
self[fetchInFlightSymbol] = false;
|
|
195
|
+
if (!self[originValuesSymbol]) {
|
|
196
|
+
self[originValuesSymbol] = clone(
|
|
197
|
+
self[datasourceLinkedElementSymbol].data,
|
|
198
|
+
);
|
|
199
|
+
updateChangesState.call(self);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
element.addEventListener("monster-datasource-error", () => {
|
|
203
|
+
self[fetchInFlightSymbol] = false;
|
|
204
|
+
});
|
|
191
205
|
}
|
|
192
206
|
|
|
193
207
|
this[datasourceLinkedElementSymbol] = element;
|
|
@@ -199,92 +213,16 @@ class SaveButton extends CustomElement {
|
|
|
199
213
|
|
|
200
214
|
element.datasource.attachObserver(
|
|
201
215
|
new Observer(function () {
|
|
216
|
+
if (self[fetchInFlightSymbol] === true) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
202
219
|
if (!self[originValuesSymbol]) {
|
|
203
220
|
self[originValuesSymbol] = clone(
|
|
204
221
|
self[datasourceLinkedElementSymbol].data,
|
|
205
222
|
);
|
|
206
223
|
}
|
|
207
224
|
|
|
208
|
-
|
|
209
|
-
const ignoreChanges = self.getOption("ignoreChanges");
|
|
210
|
-
|
|
211
|
-
const result = diff(self[originValuesSymbol], currentValues);
|
|
212
|
-
if (
|
|
213
|
-
self.getOption("logLevel") === "debug" ||
|
|
214
|
-
location.search.includes("logLevel=debug")
|
|
215
|
-
) {
|
|
216
|
-
console.groupCollapsed("SaveButton");
|
|
217
|
-
console.log(
|
|
218
|
-
"originValues",
|
|
219
|
-
JSON.parse(JSON.stringify(currentValues)),
|
|
220
|
-
);
|
|
221
|
-
console.log("result of diff", result);
|
|
222
|
-
console.log("ignoreChanges", ignoreChanges);
|
|
223
|
-
|
|
224
|
-
if (isArray(result) && result.length > 0) {
|
|
225
|
-
const formattedDiff = result.map((change) => ({
|
|
226
|
-
Operator: change?.operator,
|
|
227
|
-
Path: change?.path?.join("."),
|
|
228
|
-
"First Value": change?.first?.value,
|
|
229
|
-
"First Type": change?.first?.type,
|
|
230
|
-
"Second Value": change?.second?.value,
|
|
231
|
-
"Second Type": change?.second?.type,
|
|
232
|
-
}));
|
|
233
|
-
|
|
234
|
-
console.table(formattedDiff);
|
|
235
|
-
} else {
|
|
236
|
-
console.log("There are no changes to save");
|
|
237
|
-
}
|
|
238
|
-
console.groupEnd();
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (isArray(ignoreChanges) && ignoreChanges.length > 0) {
|
|
242
|
-
const itemsToRemove = [];
|
|
243
|
-
for (const item of result) {
|
|
244
|
-
for (const ignorePattern of ignoreChanges) {
|
|
245
|
-
const p = new RegExp(ignorePattern);
|
|
246
|
-
|
|
247
|
-
let matchPath = item.path;
|
|
248
|
-
if (isArray(item.path)) {
|
|
249
|
-
matchPath = item.path.join(".");
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (p.test(matchPath)) {
|
|
253
|
-
itemsToRemove.push(item);
|
|
254
|
-
break;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
for (const itemToRemove of itemsToRemove) {
|
|
260
|
-
const index = result.indexOf(itemToRemove);
|
|
261
|
-
if (index > -1) {
|
|
262
|
-
result.splice(index, 1);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (isArray(result) && result.length > 0) {
|
|
268
|
-
self[stateButtonElementSymbol].setState("changed");
|
|
269
|
-
self[stateButtonElementSymbol].setOption("disabled", false);
|
|
270
|
-
self.setOption("changes", result.length);
|
|
271
|
-
self.setOption(
|
|
272
|
-
"classes.badge",
|
|
273
|
-
new TokenList(self.getOption("classes.badge"))
|
|
274
|
-
.remove("hidden")
|
|
275
|
-
.toString(),
|
|
276
|
-
);
|
|
277
|
-
} else {
|
|
278
|
-
self[stateButtonElementSymbol].removeState();
|
|
279
|
-
self[stateButtonElementSymbol].setOption("disabled", true);
|
|
280
|
-
self.setOption("changes", 0);
|
|
281
|
-
self.setOption(
|
|
282
|
-
"classes.badge",
|
|
283
|
-
new TokenList(self.getOption("classes.badge"))
|
|
284
|
-
.add("hidden")
|
|
285
|
-
.toString(),
|
|
286
|
-
);
|
|
287
|
-
}
|
|
225
|
+
updateChangesState.call(self);
|
|
288
226
|
}),
|
|
289
227
|
);
|
|
290
228
|
}
|
|
@@ -440,6 +378,91 @@ function initEventHandler() {
|
|
|
440
378
|
});
|
|
441
379
|
}
|
|
442
380
|
|
|
381
|
+
/**
|
|
382
|
+
* @private
|
|
383
|
+
*/
|
|
384
|
+
function updateChangesState() {
|
|
385
|
+
const currentValues = this[datasourceLinkedElementSymbol]?.datasource?.get();
|
|
386
|
+
const ignoreChanges = this.getOption("ignoreChanges");
|
|
387
|
+
let result = diff(this[originValuesSymbol], currentValues);
|
|
388
|
+
|
|
389
|
+
if (
|
|
390
|
+
this.getOption("logLevel") === "debug" ||
|
|
391
|
+
location.search.includes("logLevel=debug")
|
|
392
|
+
) {
|
|
393
|
+
console.groupCollapsed("SaveButton");
|
|
394
|
+
console.log(
|
|
395
|
+
"originValues",
|
|
396
|
+
JSON.parse(JSON.stringify(this[originValuesSymbol])),
|
|
397
|
+
);
|
|
398
|
+
console.log("currentValues", JSON.parse(JSON.stringify(currentValues)));
|
|
399
|
+
console.log("result of diff", result);
|
|
400
|
+
console.log("ignoreChanges", ignoreChanges);
|
|
401
|
+
|
|
402
|
+
if (isArray(result) && result.length > 0) {
|
|
403
|
+
const formattedDiff = result.map((change) => ({
|
|
404
|
+
Operator: change?.operator,
|
|
405
|
+
Path: change?.path?.join("."),
|
|
406
|
+
"First Value": change?.first?.value,
|
|
407
|
+
"First Type": change?.first?.type,
|
|
408
|
+
"Second Value": change?.second?.value,
|
|
409
|
+
"Second Type": change?.second?.type,
|
|
410
|
+
}));
|
|
411
|
+
|
|
412
|
+
console.table(formattedDiff);
|
|
413
|
+
} else {
|
|
414
|
+
console.log("There are no changes to save");
|
|
415
|
+
}
|
|
416
|
+
console.groupEnd();
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (isArray(ignoreChanges) && ignoreChanges.length > 0) {
|
|
420
|
+
const itemsToRemove = [];
|
|
421
|
+
for (const item of result) {
|
|
422
|
+
for (const ignorePattern of ignoreChanges) {
|
|
423
|
+
const p = new RegExp(ignorePattern);
|
|
424
|
+
|
|
425
|
+
let matchPath = item.path;
|
|
426
|
+
if (isArray(item.path)) {
|
|
427
|
+
matchPath = item.path.join(".");
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (p.test(matchPath)) {
|
|
431
|
+
itemsToRemove.push(item);
|
|
432
|
+
break;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
for (const itemToRemove of itemsToRemove) {
|
|
438
|
+
const index = result.indexOf(itemToRemove);
|
|
439
|
+
if (index > -1) {
|
|
440
|
+
result.splice(index, 1);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (isArray(result) && result.length > 0) {
|
|
446
|
+
this[stateButtonElementSymbol].setState("changed");
|
|
447
|
+
this[stateButtonElementSymbol].setOption("disabled", false);
|
|
448
|
+
this.setOption("changes", result.length);
|
|
449
|
+
this.setOption(
|
|
450
|
+
"classes.badge",
|
|
451
|
+
new TokenList(this.getOption("classes.badge"))
|
|
452
|
+
.remove("hidden")
|
|
453
|
+
.toString(),
|
|
454
|
+
);
|
|
455
|
+
} else {
|
|
456
|
+
this[stateButtonElementSymbol].removeState();
|
|
457
|
+
this[stateButtonElementSymbol].setOption("disabled", true);
|
|
458
|
+
this.setOption("changes", 0);
|
|
459
|
+
this.setOption(
|
|
460
|
+
"classes.badge",
|
|
461
|
+
new TokenList(this.getOption("classes.badge")).add("hidden").toString(),
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
443
466
|
/**
|
|
444
467
|
* @param {Object} options
|
|
445
468
|
* @deprecated 2024-12-31
|
|
@@ -16,6 +16,7 @@ import { diff } from "../../data/diff.mjs";
|
|
|
16
16
|
import { Pathfinder } from "../../data/pathfinder.mjs";
|
|
17
17
|
import { isObject, isPrimitive } from "../../types/is.mjs";
|
|
18
18
|
import { Observer } from "../../types/observer.mjs";
|
|
19
|
+
import { clone } from "../../util/clone.mjs";
|
|
19
20
|
|
|
20
21
|
export { handleDataSourceChanges, datasourceLinkedElementSymbol };
|
|
21
22
|
|
|
@@ -29,7 +30,7 @@ const dataChangeVersionSymbol = Symbol("dataChangeVersion");
|
|
|
29
30
|
/**
|
|
30
31
|
* @private
|
|
31
32
|
*/
|
|
32
|
-
function handleDataSourceChanges() {
|
|
33
|
+
function handleDataSourceChanges(force = false) {
|
|
33
34
|
if (!this[datasourceLinkedElementSymbol]) {
|
|
34
35
|
return;
|
|
35
36
|
}
|
|
@@ -69,15 +70,20 @@ function handleDataSourceChanges() {
|
|
|
69
70
|
data = [];
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
const result = diff(data, actualDataAsObj);
|
|
73
|
-
if (result.length === 0) {
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
73
|
queueMicrotask(() => {
|
|
78
74
|
if (this[dataChangeVersionSymbol] !== version) {
|
|
79
75
|
return;
|
|
80
76
|
}
|
|
77
|
+
if (force) {
|
|
78
|
+
this.setOption("data", clone(data));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const result = diff(data, actualDataAsObj);
|
|
83
|
+
if (result.length === 0) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
81
87
|
this.setOption("data", data);
|
|
82
88
|
});
|
|
83
89
|
}
|
|
@@ -252,6 +252,11 @@ const runLookupOnceSymbol = Symbol("runLookupOnce");
|
|
|
252
252
|
* @type {symbol}
|
|
253
253
|
*/
|
|
254
254
|
const cleanupOptionsListSymbol = Symbol("cleanupOptionsList");
|
|
255
|
+
const optionsVersionSymbol = Symbol("optionsVersion");
|
|
256
|
+
const pendingSelectionSymbol = Symbol("pendingSelection");
|
|
257
|
+
const selectionSyncScheduledSymbol = Symbol("selectionSyncScheduled");
|
|
258
|
+
const optionsSnapshotSymbol = Symbol("optionsSnapshot");
|
|
259
|
+
const selectionVersionSymbol = Symbol("selectionVersion");
|
|
255
260
|
|
|
256
261
|
/**
|
|
257
262
|
* @private
|
|
@@ -950,6 +955,77 @@ function processAndApplyPaginationData(data) {
|
|
|
950
955
|
}
|
|
951
956
|
}
|
|
952
957
|
|
|
958
|
+
/**
|
|
959
|
+
* @private
|
|
960
|
+
* @returns {number}
|
|
961
|
+
*/
|
|
962
|
+
function bumpOptionsVersion() {
|
|
963
|
+
if (!isInteger(this[optionsVersionSymbol])) {
|
|
964
|
+
this[optionsVersionSymbol] = 0;
|
|
965
|
+
}
|
|
966
|
+
this[optionsVersionSymbol] += 1;
|
|
967
|
+
return this[optionsVersionSymbol];
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* @private
|
|
972
|
+
* @returns {*}
|
|
973
|
+
*/
|
|
974
|
+
function getSelectionSyncState() {
|
|
975
|
+
const attrValue = this.getAttribute("value");
|
|
976
|
+
const selection = this.getOption("selection");
|
|
977
|
+
const options = this.getOption("options");
|
|
978
|
+
const optionsLength = Array.isArray(options) ? options.length : 0;
|
|
979
|
+
return { attrValue, selection, optionsLength };
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* @private
|
|
984
|
+
* @param {number} version
|
|
985
|
+
*/
|
|
986
|
+
function scheduleSelectionSync(version) {
|
|
987
|
+
const state = getSelectionSyncState.call(this);
|
|
988
|
+
const selectionIsEmpty =
|
|
989
|
+
Array.isArray(state.selection) && state.selection.length === 0;
|
|
990
|
+
|
|
991
|
+
if (state.attrValue === null && selectionIsEmpty) {
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
const pending = {
|
|
996
|
+
version,
|
|
997
|
+
selectionVersion: this[selectionVersionSymbol] || 0,
|
|
998
|
+
value: state.attrValue !== null ? state.attrValue : state.selection,
|
|
999
|
+
};
|
|
1000
|
+
this[pendingSelectionSymbol] = pending;
|
|
1001
|
+
|
|
1002
|
+
if (this[selectionSyncScheduledSymbol] === true) {
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
this[selectionSyncScheduledSymbol] = true;
|
|
1006
|
+
|
|
1007
|
+
queueMicrotask(() => {
|
|
1008
|
+
this[selectionSyncScheduledSymbol] = false;
|
|
1009
|
+
const current = this[pendingSelectionSymbol];
|
|
1010
|
+
if (!current) {
|
|
1011
|
+
return;
|
|
1012
|
+
}
|
|
1013
|
+
if (current.version !== this[optionsVersionSymbol]) {
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
if (current.selectionVersion !== (this[selectionVersionSymbol] || 0)) {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
setSelection
|
|
1021
|
+
.call(this, current.value)
|
|
1022
|
+
.then(() => {})
|
|
1023
|
+
.catch((e) => {
|
|
1024
|
+
addErrorAttribute(this, e);
|
|
1025
|
+
});
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
|
|
953
1029
|
/**
|
|
954
1030
|
* @private
|
|
955
1031
|
* @param data
|
|
@@ -1011,8 +1087,9 @@ function importOptionsIntern(data) {
|
|
|
1011
1087
|
const map = buildMap(data, selector, labelTemplate, valueTemplate, filter);
|
|
1012
1088
|
|
|
1013
1089
|
let options = [];
|
|
1090
|
+
const currentOptions = this.getOption("options");
|
|
1014
1091
|
if (this[cleanupOptionsListSymbol] !== true) {
|
|
1015
|
-
options =
|
|
1092
|
+
options = currentOptions ?? [];
|
|
1016
1093
|
}
|
|
1017
1094
|
|
|
1018
1095
|
this[cleanupOptionsListSymbol] = false;
|
|
@@ -1092,14 +1169,10 @@ function importOptionsIntern(data) {
|
|
|
1092
1169
|
options,
|
|
1093
1170
|
});
|
|
1094
1171
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
.catch((e) => {
|
|
1100
|
-
addErrorAttribute(this, e);
|
|
1101
|
-
});
|
|
1102
|
-
}, 10);
|
|
1172
|
+
if (options === currentOptions) {
|
|
1173
|
+
const version = bumpOptionsVersion.call(this);
|
|
1174
|
+
scheduleSelectionSync.call(this, version);
|
|
1175
|
+
}
|
|
1103
1176
|
|
|
1104
1177
|
return this;
|
|
1105
1178
|
}
|
|
@@ -1672,24 +1745,13 @@ function fetchIt(url, controlOptions) {
|
|
|
1672
1745
|
|
|
1673
1746
|
this[lastFetchedDataSymbol] = map;
|
|
1674
1747
|
|
|
1675
|
-
let result;
|
|
1676
|
-
const selection = this.getOption("selection");
|
|
1677
|
-
let newValue = [];
|
|
1678
|
-
if (selection) {
|
|
1679
|
-
newValue = selection;
|
|
1680
|
-
} else if (this.hasAttribute("value")) {
|
|
1681
|
-
newValue = this.getAttribute("value");
|
|
1682
|
-
}
|
|
1683
|
-
|
|
1684
|
-
result = setSelection.call(this, newValue);
|
|
1685
|
-
|
|
1686
1748
|
queueMicrotask(() => {
|
|
1687
1749
|
checkOptionState.call(this);
|
|
1688
1750
|
setTotalText.call(this);
|
|
1689
1751
|
updatePopper.call(this);
|
|
1690
1752
|
setStatusOrRemoveBadges.call(this, "closed");
|
|
1691
1753
|
|
|
1692
|
-
resolve(
|
|
1754
|
+
resolve();
|
|
1693
1755
|
});
|
|
1694
1756
|
|
|
1695
1757
|
return;
|
|
@@ -1828,6 +1890,7 @@ function getSummaryTemplate() {
|
|
|
1828
1890
|
*/
|
|
1829
1891
|
function parseSlotsToOptions() {
|
|
1830
1892
|
let options = this.getOption("options");
|
|
1893
|
+
const currentOptions = options;
|
|
1831
1894
|
if (!isIterable(options)) {
|
|
1832
1895
|
options = [];
|
|
1833
1896
|
}
|
|
@@ -1855,6 +1918,8 @@ function parseSlotsToOptions() {
|
|
|
1855
1918
|
});
|
|
1856
1919
|
|
|
1857
1920
|
this.setOption("options", options);
|
|
1921
|
+
const version = bumpOptionsVersion.call(this);
|
|
1922
|
+
scheduleSelectionSync.call(this, version);
|
|
1858
1923
|
}
|
|
1859
1924
|
|
|
1860
1925
|
/**
|
|
@@ -2041,6 +2106,13 @@ function initOptionObserver() {
|
|
|
2041
2106
|
|
|
2042
2107
|
self.attachObserver(
|
|
2043
2108
|
new Observer(function () {
|
|
2109
|
+
const options = self.getOption("options");
|
|
2110
|
+
if (options !== self[optionsSnapshotSymbol]) {
|
|
2111
|
+
self[optionsSnapshotSymbol] = options;
|
|
2112
|
+
const version = bumpOptionsVersion.call(self);
|
|
2113
|
+
scheduleSelectionSync.call(self, version);
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2044
2116
|
new Processing(() => {
|
|
2045
2117
|
try {
|
|
2046
2118
|
self.updateI18n();
|
|
@@ -2782,6 +2854,11 @@ function gatherState() {
|
|
|
2782
2854
|
throw new Error("no shadow-root is defined");
|
|
2783
2855
|
}
|
|
2784
2856
|
|
|
2857
|
+
const inputElements = this.shadowRoot.querySelectorAll(`input[type=${type}]`);
|
|
2858
|
+
if (inputElements.length === 0) {
|
|
2859
|
+
return this;
|
|
2860
|
+
}
|
|
2861
|
+
|
|
2785
2862
|
let filteredSelection = [];
|
|
2786
2863
|
if (type === "radio") {
|
|
2787
2864
|
const selection = [];
|
|
@@ -2799,7 +2876,7 @@ function gatherState() {
|
|
|
2799
2876
|
filteredSelection = selection;
|
|
2800
2877
|
} else {
|
|
2801
2878
|
const selection = [...this.getOption("selection", [])];
|
|
2802
|
-
const allElements =
|
|
2879
|
+
const allElements = inputElements;
|
|
2803
2880
|
const checkedElements = this.shadowRoot.querySelectorAll(
|
|
2804
2881
|
`input[type=${type}]:checked`,
|
|
2805
2882
|
);
|
|
@@ -3003,6 +3080,10 @@ function areOptionsAvailableAndInitInternal() {
|
|
|
3003
3080
|
|
|
3004
3081
|
if (updated) {
|
|
3005
3082
|
this.setOption("options", options);
|
|
3083
|
+
if (options === currentOptions) {
|
|
3084
|
+
const version = bumpOptionsVersion.call(this);
|
|
3085
|
+
scheduleSelectionSync.call(this, version);
|
|
3086
|
+
}
|
|
3006
3087
|
}
|
|
3007
3088
|
|
|
3008
3089
|
setStatusOrRemoveBadges.call(this);
|
|
@@ -3033,11 +3114,19 @@ function checkOptionState() {
|
|
|
3033
3114
|
return a.value;
|
|
3034
3115
|
});
|
|
3035
3116
|
|
|
3117
|
+
const CLASSNAME = "selected";
|
|
3036
3118
|
for (const e of elements) {
|
|
3119
|
+
const parent = e.closest(`[${ATTRIBUTE_ROLE}=option]`);
|
|
3037
3120
|
if (checkedValues.indexOf(e.value) !== -1) {
|
|
3038
3121
|
if (e.checked !== true) e.checked = true;
|
|
3122
|
+
if (parent) {
|
|
3123
|
+
parent.classList.add(CLASSNAME);
|
|
3124
|
+
}
|
|
3039
3125
|
} else {
|
|
3040
3126
|
if (e.checked !== false) e.checked = false;
|
|
3127
|
+
if (parent) {
|
|
3128
|
+
parent.classList.remove(CLASSNAME);
|
|
3129
|
+
}
|
|
3041
3130
|
}
|
|
3042
3131
|
}
|
|
3043
3132
|
}
|
|
@@ -3188,6 +3277,11 @@ function setSelection(selection) {
|
|
|
3188
3277
|
|
|
3189
3278
|
selection = resultSelection;
|
|
3190
3279
|
|
|
3280
|
+
if (!isInteger(this[selectionVersionSymbol])) {
|
|
3281
|
+
this[selectionVersionSymbol] = 0;
|
|
3282
|
+
}
|
|
3283
|
+
this[selectionVersionSymbol] += 1;
|
|
3284
|
+
|
|
3191
3285
|
this.setOption("selection", selection);
|
|
3192
3286
|
|
|
3193
3287
|
checkOptionState.call(this);
|
|
@@ -916,14 +916,14 @@ function getTemplate() {
|
|
|
916
916
|
// language=HTML
|
|
917
917
|
return `
|
|
918
918
|
<div data-monster-role="control" part="control">
|
|
919
|
-
<div class="prev" data-monster-role="prev" part="prev">
|
|
919
|
+
<div class="prev hidden" data-monster-role="prev" part="prev">
|
|
920
920
|
<slot name="prev"></slot>
|
|
921
921
|
</div>
|
|
922
922
|
<div data-monster-role="slider" part="slides">
|
|
923
923
|
<slot></slot>
|
|
924
924
|
</div>
|
|
925
|
-
<div data-monster-role="thumbnails" part="thumbnails"></div>
|
|
926
|
-
<div class="next" data-monster-role="next" part="next">
|
|
925
|
+
<div class="hidden" data-monster-role="thumbnails" part="thumbnails"></div>
|
|
926
|
+
<div class="next hidden" data-monster-role="next" part="next">
|
|
927
927
|
<slot name="next"></slot>
|
|
928
928
|
</div>
|
|
929
929
|
</div>`;
|
|
@@ -98,6 +98,12 @@ const attributeObserverSymbol = Symbol.for(
|
|
|
98
98
|
const attributeMutationObserverSymbol = Symbol(
|
|
99
99
|
"@schukai/monster/dom/@@mutationObserver",
|
|
100
100
|
);
|
|
101
|
+
const childMutationObserverSymbol = Symbol(
|
|
102
|
+
"@schukai/monster/dom/@@childMutationObserver",
|
|
103
|
+
);
|
|
104
|
+
const childMutationTimerSymbol = Symbol(
|
|
105
|
+
"@schukai/monster/dom/@@childMutationTimer",
|
|
106
|
+
);
|
|
101
107
|
|
|
102
108
|
/**
|
|
103
109
|
* @private
|
|
@@ -221,6 +227,9 @@ class CustomElement extends HTMLElement {
|
|
|
221
227
|
this[initMethodSymbol]();
|
|
222
228
|
initOptionObserver.call(this);
|
|
223
229
|
this[scriptHostElementSymbol] = [];
|
|
230
|
+
// Catch attribute changes made before connectedCallback runs.
|
|
231
|
+
attachAttributeChangeMutationObserver.call(this);
|
|
232
|
+
attachChildMutationObserver.call(this);
|
|
224
233
|
}
|
|
225
234
|
|
|
226
235
|
/**
|
|
@@ -679,6 +688,14 @@ class CustomElement extends HTMLElement {
|
|
|
679
688
|
connectedCallback() {
|
|
680
689
|
// Check if the object has already been initialized
|
|
681
690
|
if (!hasObjectLink(this, customElementUpdaterLinkSymbol)) {
|
|
691
|
+
try {
|
|
692
|
+
initOptionsFromAttributes(
|
|
693
|
+
this,
|
|
694
|
+
this[internalSymbol].getSubject()?.["options"],
|
|
695
|
+
);
|
|
696
|
+
} catch (e) {
|
|
697
|
+
addErrorAttribute(this, e);
|
|
698
|
+
}
|
|
682
699
|
// If not, call the assembleMethod to initialize the object
|
|
683
700
|
this[assembleMethodSymbol]();
|
|
684
701
|
}
|
|
@@ -874,6 +891,65 @@ function attachAttributeChangeMutationObserver() {
|
|
|
874
891
|
}
|
|
875
892
|
}
|
|
876
893
|
|
|
894
|
+
/**
|
|
895
|
+
* @private
|
|
896
|
+
* @this CustomElement
|
|
897
|
+
*/
|
|
898
|
+
function attachChildMutationObserver() {
|
|
899
|
+
const self = this;
|
|
900
|
+
|
|
901
|
+
if (self[childMutationObserverSymbol]) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
if (self.getOption("features.mutationObserver") !== true) {
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
self[childMutationObserverSymbol] = new MutationObserver((mutations) => {
|
|
910
|
+
let hasAdditions = false;
|
|
911
|
+
for (const mutation of mutations) {
|
|
912
|
+
if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
|
|
913
|
+
hasAdditions = true;
|
|
914
|
+
break;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
if (!hasAdditions) {
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
if (self[childMutationTimerSymbol]) {
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
self[childMutationTimerSymbol] = setTimeout(() => {
|
|
927
|
+
self[childMutationTimerSymbol] = null;
|
|
928
|
+
if (!hasObjectLink(self, customElementUpdaterLinkSymbol)) {
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const updaters = getLinkedObjects(self, customElementUpdaterLinkSymbol);
|
|
933
|
+
for (const list of updaters) {
|
|
934
|
+
for (const updater of list) {
|
|
935
|
+
updater.run().catch((e) => {
|
|
936
|
+
addErrorAttribute(self, e);
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}, 50);
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
try {
|
|
944
|
+
self[childMutationObserverSymbol].observe(self, {
|
|
945
|
+
childList: true,
|
|
946
|
+
subtree: true,
|
|
947
|
+
});
|
|
948
|
+
} catch (e) {
|
|
949
|
+
addErrorAttribute(self, e);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
877
953
|
/**
|
|
878
954
|
* @this CustomElement
|
|
879
955
|
* @private
|
package/source/dom/updater.mjs
CHANGED
|
@@ -1075,6 +1075,10 @@ function handleInputControlAttributeUpdate(element, name, value) {
|
|
|
1075
1075
|
if (name === "value") {
|
|
1076
1076
|
element.value = value === undefined ? "" : value;
|
|
1077
1077
|
}
|
|
1078
|
+
} else if (name === "value" && element instanceof CustomElement) {
|
|
1079
|
+
if ("value" in element) {
|
|
1080
|
+
element.value = value === undefined ? "" : value;
|
|
1081
|
+
}
|
|
1078
1082
|
}
|
|
1079
1083
|
}
|
|
1080
1084
|
|