@schukai/monster 4.124.2 → 4.125.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/filter.mjs +13 -3
- package/source/components/form/toggle-switch.mjs +31 -0
- package/source/dom/constants.mjs +8 -0
- package/source/dom/updater.mjs +275 -0
- package/test/cases/components/form/toggle-switch.mjs +15 -0
- package/test/cases/dom/updater.mjs +113 -2
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.5","@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.5","@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.125.0"}
|
|
@@ -1311,8 +1311,14 @@ function collectSearchQueries() {
|
|
|
1311
1311
|
}
|
|
1312
1312
|
|
|
1313
1313
|
const controlValue = getControlValuesFromLabel(element);
|
|
1314
|
-
|
|
1315
|
-
|
|
1314
|
+
const hasEmptyArrayValue =
|
|
1315
|
+
isArray(controlValue) && controlValue.length === 0;
|
|
1316
|
+
|
|
1317
|
+
if (!controlValue || hasEmptyArrayValue) {
|
|
1318
|
+
if (
|
|
1319
|
+
(controlValue === "" || hasEmptyArrayValue) &&
|
|
1320
|
+
currentHash?.[this.id]?.[id]
|
|
1321
|
+
) {
|
|
1316
1322
|
delete currentHash[this.id][id];
|
|
1317
1323
|
}
|
|
1318
1324
|
|
|
@@ -1324,9 +1330,13 @@ function collectSearchQueries() {
|
|
|
1324
1330
|
}
|
|
1325
1331
|
currentHash[this.id][id] = controlValue;
|
|
1326
1332
|
|
|
1333
|
+
const formatterValue = isArray(controlValue)
|
|
1334
|
+
? controlValue.join(",")
|
|
1335
|
+
: controlValue;
|
|
1336
|
+
|
|
1327
1337
|
const mapping = {
|
|
1328
1338
|
id,
|
|
1329
|
-
value:
|
|
1339
|
+
value: formatterValue,
|
|
1330
1340
|
label,
|
|
1331
1341
|
};
|
|
1332
1342
|
|
|
@@ -297,6 +297,8 @@ class ToggleSwitch extends CustomControl {
|
|
|
297
297
|
) {
|
|
298
298
|
if (this.getOption("value") !== normalized) {
|
|
299
299
|
this.setOption("value", normalized);
|
|
300
|
+
} else {
|
|
301
|
+
validateAndSetValue.call(this);
|
|
300
302
|
}
|
|
301
303
|
return;
|
|
302
304
|
}
|
|
@@ -350,6 +352,7 @@ function toggleOn() {
|
|
|
350
352
|
return;
|
|
351
353
|
}
|
|
352
354
|
|
|
355
|
+
this[switchElementSymbol].classList.remove(this.getOption("classes.error"));
|
|
353
356
|
this[switchElementSymbol].classList.remove(this.getOption("classes.off")); // change color
|
|
354
357
|
this[switchElementSymbol].classList.add(this.getOption("classes.on")); // change color
|
|
355
358
|
|
|
@@ -371,6 +374,7 @@ function toggleOff() {
|
|
|
371
374
|
return;
|
|
372
375
|
}
|
|
373
376
|
|
|
377
|
+
this[switchElementSymbol].classList.remove(this.getOption("classes.error"));
|
|
374
378
|
this[switchElementSymbol].classList.remove(this.getOption("classes.on")); // change color
|
|
375
379
|
this[switchElementSymbol].classList.add(this.getOption("classes.off")); // change color
|
|
376
380
|
|
|
@@ -397,6 +401,17 @@ function showError() {
|
|
|
397
401
|
this[switchElementSymbol].classList.add(this.getOption("classes.error"));
|
|
398
402
|
}
|
|
399
403
|
|
|
404
|
+
/**
|
|
405
|
+
* @private
|
|
406
|
+
*/
|
|
407
|
+
function clearError() {
|
|
408
|
+
if (this[switchElementSymbol]) {
|
|
409
|
+
this[switchElementSymbol].classList.remove(this.getOption("classes.error"));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
this.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
|
|
413
|
+
}
|
|
414
|
+
|
|
400
415
|
/**
|
|
401
416
|
* @private
|
|
402
417
|
*/
|
|
@@ -407,6 +422,21 @@ function validateAndSetValue() {
|
|
|
407
422
|
this.setOption("value", value);
|
|
408
423
|
}
|
|
409
424
|
|
|
425
|
+
const offValue = this.getOption("values.off");
|
|
426
|
+
if (value === undefined || value === null || value === "") {
|
|
427
|
+
clearError.call(this);
|
|
428
|
+
if (this[invalidDisabledSymbol]) {
|
|
429
|
+
this.setOption("disabled", false);
|
|
430
|
+
this.formDisabledCallback(false);
|
|
431
|
+
this[invalidDisabledSymbol] = false;
|
|
432
|
+
}
|
|
433
|
+
if (this.getOption("value") !== offValue) {
|
|
434
|
+
this.setOption("value", offValue);
|
|
435
|
+
}
|
|
436
|
+
toggleOff.call(this);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
410
440
|
const validatedValues = [];
|
|
411
441
|
validatedValues.push(this.getOption("values.on"));
|
|
412
442
|
validatedValues.push(this.getOption("values.off"));
|
|
@@ -437,6 +467,7 @@ function validateAndSetValue() {
|
|
|
437
467
|
this.formDisabledCallback(false);
|
|
438
468
|
this[invalidDisabledSymbol] = false;
|
|
439
469
|
}
|
|
470
|
+
clearError.call(this);
|
|
440
471
|
|
|
441
472
|
if (value === this.getOption("values.on")) {
|
|
442
473
|
toggleOn.call(this);
|
package/source/dom/constants.mjs
CHANGED
|
@@ -20,6 +20,7 @@ export {
|
|
|
20
20
|
ATTRIBUTE_THEME_PREFIX,
|
|
21
21
|
ATTRIBUTE_THEME_NAME,
|
|
22
22
|
ATTRIBUTE_UPDATER_ATTRIBUTES,
|
|
23
|
+
ATTRIBUTE_UPDATER_PROPERTIES,
|
|
23
24
|
ATTRIBUTE_UPDATER_SELECT_THIS,
|
|
24
25
|
ATTRIBUTE_UPDATER_REPLACE,
|
|
25
26
|
ATTRIBUTE_UPDATER_INSERT,
|
|
@@ -151,6 +152,13 @@ const ATTRIBUTE_THEME_NAME = `${ATTRIBUTE_THEME_PREFIX}name`;
|
|
|
151
152
|
*/
|
|
152
153
|
const ATTRIBUTE_UPDATER_ATTRIBUTES = `${ATTRIBUTE_PREFIX}attributes`;
|
|
153
154
|
|
|
155
|
+
/**
|
|
156
|
+
* @type {string}
|
|
157
|
+
* @license AGPLv3
|
|
158
|
+
* @since 4.125.0
|
|
159
|
+
*/
|
|
160
|
+
const ATTRIBUTE_UPDATER_PROPERTIES = `${ATTRIBUTE_PREFIX}properties`;
|
|
161
|
+
|
|
154
162
|
/**
|
|
155
163
|
* @type {string}
|
|
156
164
|
* @license AGPLv3
|
package/source/dom/updater.mjs
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
ATTRIBUTE_UPDATER_BIND_TYPE,
|
|
24
24
|
ATTRIBUTE_UPDATER_INSERT,
|
|
25
25
|
ATTRIBUTE_UPDATER_INSERT_REFERENCE,
|
|
26
|
+
ATTRIBUTE_UPDATER_PROPERTIES,
|
|
26
27
|
ATTRIBUTE_UPDATER_REMOVE,
|
|
27
28
|
ATTRIBUTE_UPDATER_REPLACE,
|
|
28
29
|
ATTRIBUTE_UPDATER_SELECT_THIS,
|
|
@@ -190,6 +191,7 @@ class Updater extends Base {
|
|
|
190
191
|
for (const path of updatePaths.values()) {
|
|
191
192
|
updateContent.call(this, { path });
|
|
192
193
|
updateAttributes.call(this, { path });
|
|
194
|
+
updateProperties.call(this, { path });
|
|
193
195
|
}
|
|
194
196
|
} else {
|
|
195
197
|
for (const change of Object.values(diffResult)) {
|
|
@@ -211,6 +213,7 @@ class Updater extends Base {
|
|
|
211
213
|
updateContent.call(this, change);
|
|
212
214
|
await Promise.resolve();
|
|
213
215
|
updateAttributes.call(this, change);
|
|
216
|
+
updateProperties.call(this, change);
|
|
214
217
|
}
|
|
215
218
|
|
|
216
219
|
/**
|
|
@@ -855,6 +858,14 @@ function applyRecursive(node, key, path) {
|
|
|
855
858
|
);
|
|
856
859
|
}
|
|
857
860
|
|
|
861
|
+
if (node.hasAttribute(ATTRIBUTE_UPDATER_PROPERTIES)) {
|
|
862
|
+
const value = node.getAttribute(ATTRIBUTE_UPDATER_PROPERTIES);
|
|
863
|
+
node.setAttribute(
|
|
864
|
+
ATTRIBUTE_UPDATER_PROPERTIES,
|
|
865
|
+
value.replaceAll(`path:${key}`, `path:${path}`),
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
|
|
858
869
|
if (node.hasAttribute(ATTRIBUTE_UPDATER_BIND)) {
|
|
859
870
|
const value = node.getAttribute(ATTRIBUTE_UPDATER_BIND);
|
|
860
871
|
node.setAttribute(
|
|
@@ -984,6 +995,18 @@ function updateAttributes(change) {
|
|
|
984
995
|
runUpdateAttributes.call(this, this[internalSymbol].element, p, subject);
|
|
985
996
|
}
|
|
986
997
|
|
|
998
|
+
/**
|
|
999
|
+
* @private
|
|
1000
|
+
* @since 4.125.0
|
|
1001
|
+
* @param {object} change
|
|
1002
|
+
* @return {void}
|
|
1003
|
+
*/
|
|
1004
|
+
function updateProperties(change) {
|
|
1005
|
+
const subject = this[internalSymbol].subject.getRealSubject();
|
|
1006
|
+
const p = clone(change?.["path"]);
|
|
1007
|
+
runUpdateProperties.call(this, this[internalSymbol].element, p, subject);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
987
1010
|
/**
|
|
988
1011
|
* @private
|
|
989
1012
|
* @param {HTMLElement} container
|
|
@@ -1059,6 +1082,75 @@ function runUpdateAttributes(container, parts, subject) {
|
|
|
1059
1082
|
}
|
|
1060
1083
|
}
|
|
1061
1084
|
|
|
1085
|
+
/**
|
|
1086
|
+
* @private
|
|
1087
|
+
* @param {HTMLElement} container
|
|
1088
|
+
* @param {array} parts
|
|
1089
|
+
* @param {object} subject
|
|
1090
|
+
* @return {void}
|
|
1091
|
+
* @this Updater
|
|
1092
|
+
*/
|
|
1093
|
+
function runUpdateProperties(container, parts, subject) {
|
|
1094
|
+
if (!isArray(parts)) return;
|
|
1095
|
+
parts = clone(parts);
|
|
1096
|
+
|
|
1097
|
+
const mem = new WeakSet();
|
|
1098
|
+
|
|
1099
|
+
while (parts.length > 0) {
|
|
1100
|
+
const current = parts.join(".");
|
|
1101
|
+
parts.pop();
|
|
1102
|
+
|
|
1103
|
+
let iterator = new Set();
|
|
1104
|
+
|
|
1105
|
+
const query = `[${ATTRIBUTE_UPDATER_SELECT_THIS}][${ATTRIBUTE_UPDATER_PROPERTIES}], [${ATTRIBUTE_UPDATER_PROPERTIES}*="path:${current}"], [${ATTRIBUTE_UPDATER_PROPERTIES}^="static:"], [${ATTRIBUTE_UPDATER_PROPERTIES}^="i18n:"]`;
|
|
1106
|
+
|
|
1107
|
+
const e = container.querySelectorAll(query);
|
|
1108
|
+
|
|
1109
|
+
if (e.length > 0) {
|
|
1110
|
+
iterator = new Set([...e]);
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
if (container.matches(query)) {
|
|
1114
|
+
iterator.add(container);
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
for (const [element] of iterator.entries()) {
|
|
1118
|
+
if (mem.has(element)) return;
|
|
1119
|
+
mem.add(element);
|
|
1120
|
+
|
|
1121
|
+
// this case occurs when the ATTRIBUTE_UPDATER_SELECT_THIS attribute is set
|
|
1122
|
+
if (!element.hasAttribute(ATTRIBUTE_UPDATER_PROPERTIES)) {
|
|
1123
|
+
continue;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
const properties = element.getAttribute(ATTRIBUTE_UPDATER_PROPERTIES);
|
|
1127
|
+
|
|
1128
|
+
for (let [, def] of Object.entries(properties.split(","))) {
|
|
1129
|
+
def = trimSpaces(def);
|
|
1130
|
+
const i = def.indexOf(" ");
|
|
1131
|
+
const name = trimSpaces(def.substr(0, i));
|
|
1132
|
+
const cmd = trimSpaces(def.substr(i));
|
|
1133
|
+
|
|
1134
|
+
const pipe = new Pipe(cmd);
|
|
1135
|
+
|
|
1136
|
+
this[internalSymbol].callbacks.forEach((f, n) => {
|
|
1137
|
+
pipe.setCallback(n, f, element);
|
|
1138
|
+
});
|
|
1139
|
+
|
|
1140
|
+
let value;
|
|
1141
|
+
try {
|
|
1142
|
+
element.removeAttribute(ATTRIBUTE_ERRORMESSAGE);
|
|
1143
|
+
value = pipe.run(subject);
|
|
1144
|
+
} catch (e) {
|
|
1145
|
+
addErrorAttribute(element, e);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
handleInputControlPropertyUpdate.call(this, element, name, value);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1062
1154
|
/**
|
|
1063
1155
|
* @private
|
|
1064
1156
|
* @param {HTMLElement|*} element
|
|
@@ -1133,6 +1225,189 @@ function handleInputControlAttributeUpdate(element, name, value) {
|
|
|
1133
1225
|
}
|
|
1134
1226
|
}
|
|
1135
1227
|
|
|
1228
|
+
/**
|
|
1229
|
+
* @private
|
|
1230
|
+
* @param {HTMLElement|*} element
|
|
1231
|
+
* @param {string} name
|
|
1232
|
+
* @param {*} value
|
|
1233
|
+
* @return {void}
|
|
1234
|
+
* @this Updater
|
|
1235
|
+
*/
|
|
1236
|
+
function handleInputControlPropertyUpdate(element, name, value) {
|
|
1237
|
+
if (element instanceof HTMLSelectElement && name === "value") {
|
|
1238
|
+
switch (element.type) {
|
|
1239
|
+
case "select-multiple":
|
|
1240
|
+
if (isArray(value)) {
|
|
1241
|
+
for (const [, opt] of Object.entries(element.options)) {
|
|
1242
|
+
opt.selected = value.indexOf(opt.value) !== -1;
|
|
1243
|
+
}
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
break;
|
|
1247
|
+
case "select-one":
|
|
1248
|
+
if (value === undefined) {
|
|
1249
|
+
element.selectedIndex = -1;
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
break;
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
if (element instanceof HTMLInputElement) {
|
|
1257
|
+
switch (name) {
|
|
1258
|
+
case "checked":
|
|
1259
|
+
element.checked =
|
|
1260
|
+
value === true || value === "true" || value === "1" || value === "on";
|
|
1261
|
+
return;
|
|
1262
|
+
case "value":
|
|
1263
|
+
if (element.type === "color") {
|
|
1264
|
+
if (value === undefined || value === "") {
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
break;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
if (element instanceof HTMLTextAreaElement && name === "value") {
|
|
1273
|
+
element.value = value === undefined ? "" : value;
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
const optionPath = getControlOptionPathFromPropertyName(name);
|
|
1278
|
+
if (
|
|
1279
|
+
optionPath !== null &&
|
|
1280
|
+
typeof element?.setOption === "function" &&
|
|
1281
|
+
typeof element?.getOption === "function"
|
|
1282
|
+
) {
|
|
1283
|
+
try {
|
|
1284
|
+
const current = element.getOption(optionPath);
|
|
1285
|
+
const normalized = normalizeValueForOptionTarget(value, current);
|
|
1286
|
+
element.setOption(optionPath, normalized);
|
|
1287
|
+
} catch (e) {
|
|
1288
|
+
addErrorAttribute(element, e);
|
|
1289
|
+
}
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
if (
|
|
1294
|
+
optionPath !== null &&
|
|
1295
|
+
typeof element?.setOption === "function" &&
|
|
1296
|
+
typeof element?.getOption !== "function"
|
|
1297
|
+
) {
|
|
1298
|
+
try {
|
|
1299
|
+
element.setOption(optionPath, value);
|
|
1300
|
+
} catch (e) {
|
|
1301
|
+
addErrorAttribute(element, e);
|
|
1302
|
+
}
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
try {
|
|
1307
|
+
element[name] = value;
|
|
1308
|
+
} catch (e) {
|
|
1309
|
+
addErrorAttribute(element, e);
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
/**
|
|
1314
|
+
* @private
|
|
1315
|
+
* @param {string} name
|
|
1316
|
+
* @return {string|null}
|
|
1317
|
+
*/
|
|
1318
|
+
function getControlOptionPathFromPropertyName(name) {
|
|
1319
|
+
if (!isString(name)) {
|
|
1320
|
+
return null;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
let path = null;
|
|
1324
|
+
|
|
1325
|
+
if (name.startsWith("option:")) {
|
|
1326
|
+
path = name.substring(7);
|
|
1327
|
+
} else if (name.startsWith("option.")) {
|
|
1328
|
+
path = name.substring(7);
|
|
1329
|
+
} else if (name.startsWith("options.")) {
|
|
1330
|
+
path = name.substring(8);
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
if (!isString(path)) {
|
|
1334
|
+
return null;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
path = path
|
|
1338
|
+
.split(".")
|
|
1339
|
+
.map((part) => trimSpaces(part))
|
|
1340
|
+
.filter((part) => part !== "")
|
|
1341
|
+
.join(".");
|
|
1342
|
+
|
|
1343
|
+
if (path === "") {
|
|
1344
|
+
return null;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
return path;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
/**
|
|
1351
|
+
* @private
|
|
1352
|
+
* @param {*} value
|
|
1353
|
+
* @param {*} current
|
|
1354
|
+
* @return {*}
|
|
1355
|
+
*/
|
|
1356
|
+
function normalizeValueForOptionTarget(value, current) {
|
|
1357
|
+
if (current === undefined || current === null) {
|
|
1358
|
+
return value;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
if (typeof current === "boolean") {
|
|
1362
|
+
return (
|
|
1363
|
+
value === true || value === "true" || value === "1" || value === "on"
|
|
1364
|
+
);
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
if (typeof current === "number") {
|
|
1368
|
+
const numberValue = Number(value);
|
|
1369
|
+
return isNaN(numberValue) ? current : numberValue;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
if (typeof current === "string") {
|
|
1373
|
+
return value === undefined || value === null ? "" : `${value}`;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
if (isArray(current)) {
|
|
1377
|
+
if (isArray(value)) {
|
|
1378
|
+
return value;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
if (isString(value)) {
|
|
1382
|
+
if (value.trim() === "") {
|
|
1383
|
+
return [];
|
|
1384
|
+
}
|
|
1385
|
+
return value.split("::");
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
if (value === undefined || value === null) {
|
|
1389
|
+
return [];
|
|
1390
|
+
}
|
|
1391
|
+
return [value];
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
if (typeof current === "object") {
|
|
1395
|
+
if (value !== null && typeof value === "object") {
|
|
1396
|
+
return value;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
if (isString(value)) {
|
|
1400
|
+
try {
|
|
1401
|
+
return JSON.parse(value);
|
|
1402
|
+
} catch (e) {
|
|
1403
|
+
return current;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
return value;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1136
1411
|
/**
|
|
1137
1412
|
* @param {NodeList|HTMLElement|Set<HTMLElement>} elements
|
|
1138
1413
|
* @param {Symbol} symbol
|
|
@@ -397,6 +397,21 @@ describe('ToggleSwitch', function () {
|
|
|
397
397
|
|
|
398
398
|
});
|
|
399
399
|
|
|
400
|
+
it('does not set error state for empty initial values', function (done) {
|
|
401
|
+
|
|
402
|
+
const toggleSwitch = document.createElement('monster-toggle-switch');
|
|
403
|
+
toggleSwitch.setOption('value', undefined);
|
|
404
|
+
document.getElementById('mocks').appendChild(toggleSwitch);
|
|
405
|
+
|
|
406
|
+
setTimeout(() => {
|
|
407
|
+
const switchEl = toggleSwitch.shadowRoot.querySelector('[data-monster-role="switch"]');
|
|
408
|
+
expect(toggleSwitch.getAttribute('data-monster-error')).is.equal(null);
|
|
409
|
+
expect(switchEl.classList.contains(toggleSwitch.getOption('classes.error'))).is.false;
|
|
410
|
+
expect(toggleSwitch.value).is.equal(toggleSwitch.getOption('values.off'));
|
|
411
|
+
done();
|
|
412
|
+
}, 0);
|
|
413
|
+
});
|
|
414
|
+
|
|
400
415
|
});
|
|
401
416
|
|
|
402
417
|
|
|
@@ -48,6 +48,11 @@ let html1 = `
|
|
|
48
48
|
|
|
49
49
|
<textarea name="textarea" id="textarea" data-monster-attributes="value path:a.textarea"></textarea>
|
|
50
50
|
|
|
51
|
+
<input id="property-checkbox" type="checkbox" data-monster-properties="checked path:a.checkboxBool">
|
|
52
|
+
<input id="property-input" type="text" data-monster-properties="value path:a.checkboxBool">
|
|
53
|
+
<monster-test-property id="property-custom" data-monster-properties="active path:a.checkboxBool, payload path:a.payload"></monster-test-property>
|
|
54
|
+
<monster-test-option-control id="property-option-control" data-monster-properties="option:features.enabled path:a.checkboxBool, option:labels.count path:a.optionCount"></monster-test-option-control>
|
|
55
|
+
|
|
51
56
|
</div>
|
|
52
57
|
</div>
|
|
53
58
|
|
|
@@ -64,7 +69,7 @@ let html2 = `
|
|
|
64
69
|
let html3 = `
|
|
65
70
|
|
|
66
71
|
<template id="myinnerid">
|
|
67
|
-
<span data-monster-replace="path:myinnerid | tojson"></span>
|
|
72
|
+
<span data-monster-replace="path:myinnerid | tojson" data-monster-properties="title path:myinnerid.i"></span>
|
|
68
73
|
</template>
|
|
69
74
|
|
|
70
75
|
<template id="myid">
|
|
@@ -127,6 +132,67 @@ describe("DOM", function () {
|
|
|
127
132
|
import("../../../source/dom/updater.mjs")
|
|
128
133
|
.then((m) => {
|
|
129
134
|
Updater = m.Updater;
|
|
135
|
+
|
|
136
|
+
if (!customElements.get("monster-test-property")) {
|
|
137
|
+
class MonsterTestProperty extends HTMLElement {
|
|
138
|
+
set active(value) {
|
|
139
|
+
this._active = value;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get active() {
|
|
143
|
+
return this._active;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
set payload(value) {
|
|
147
|
+
this._payload = value;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get payload() {
|
|
151
|
+
return this._payload;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
customElements.define("monster-test-property", MonsterTestProperty);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!customElements.get("monster-test-option-control")) {
|
|
159
|
+
class MonsterTestOptionControl extends HTMLElement {
|
|
160
|
+
constructor() {
|
|
161
|
+
super();
|
|
162
|
+
this._options = {
|
|
163
|
+
features: {
|
|
164
|
+
enabled: false,
|
|
165
|
+
},
|
|
166
|
+
labels: {
|
|
167
|
+
count: 0,
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
getOption(path) {
|
|
173
|
+
return path.split(".").reduce((ref, part) => ref?.[part], this._options);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
setOption(path, value) {
|
|
177
|
+
const parts = path.split(".");
|
|
178
|
+
let ref = this._options;
|
|
179
|
+
while (parts.length > 1) {
|
|
180
|
+
const part = parts.shift();
|
|
181
|
+
if (ref[part] === undefined || ref[part] === null) {
|
|
182
|
+
ref[part] = {};
|
|
183
|
+
}
|
|
184
|
+
ref = ref[part];
|
|
185
|
+
}
|
|
186
|
+
ref[parts[0]] = value;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
customElements.define(
|
|
191
|
+
"monster-test-option-control",
|
|
192
|
+
MonsterTestOptionControl,
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
130
196
|
done();
|
|
131
197
|
})
|
|
132
198
|
.catch((e) => {
|
|
@@ -714,8 +780,12 @@ describe("DOM", function () {
|
|
|
714
780
|
'<p data-monster-insert="myinnerid path:a.b" data-monster-insert-reference="myid-0">',
|
|
715
781
|
);
|
|
716
782
|
expect(element).contain.html(
|
|
717
|
-
'
|
|
783
|
+
'data-monster-replace="path:a.b.0 | tojson"',
|
|
784
|
+
);
|
|
785
|
+
expect(element).contain.html(
|
|
786
|
+
'data-monster-properties="title path:a.b.0.i"',
|
|
718
787
|
);
|
|
788
|
+
expect(element).contain.html('title="0"');
|
|
719
789
|
|
|
720
790
|
done();
|
|
721
791
|
}, 100);
|
|
@@ -750,6 +820,22 @@ describe("DOM", function () {
|
|
|
750
820
|
let textarea = document.getElementById("textarea");
|
|
751
821
|
expect(textarea.value).to.be.equal("");
|
|
752
822
|
|
|
823
|
+
let propertyCheckbox = document.getElementById("property-checkbox");
|
|
824
|
+
expect(propertyCheckbox.checked).to.be.false;
|
|
825
|
+
|
|
826
|
+
let propertyInput = document.getElementById("property-input");
|
|
827
|
+
expect(propertyInput.value).to.be.equal("");
|
|
828
|
+
|
|
829
|
+
let propertyCustom = document.getElementById("property-custom");
|
|
830
|
+
expect(propertyCustom.active).to.be.equal(undefined);
|
|
831
|
+
expect(propertyCustom.payload).to.be.equal(undefined);
|
|
832
|
+
|
|
833
|
+
let propertyOptionControl = document.getElementById(
|
|
834
|
+
"property-option-control",
|
|
835
|
+
);
|
|
836
|
+
expect(propertyOptionControl.getOption("features.enabled")).to.be.false;
|
|
837
|
+
expect(propertyOptionControl.getOption("labels.count")).to.be.equal(0);
|
|
838
|
+
|
|
753
839
|
let d = new Updater(element, {
|
|
754
840
|
a: {
|
|
755
841
|
b: "div-class",
|
|
@@ -760,6 +846,11 @@ describe("DOM", function () {
|
|
|
760
846
|
multiselect: ["value3", "value4", "other-value5"],
|
|
761
847
|
select: "value2",
|
|
762
848
|
checkbox: "true",
|
|
849
|
+
checkboxBool: true,
|
|
850
|
+
optionCount: 1234,
|
|
851
|
+
payload: {
|
|
852
|
+
state: "ok",
|
|
853
|
+
},
|
|
763
854
|
},
|
|
764
855
|
});
|
|
765
856
|
|
|
@@ -800,6 +891,26 @@ describe("DOM", function () {
|
|
|
800
891
|
"multiselect control",
|
|
801
892
|
).to.be.equal(JSON.stringify(d.getSubject()["a"]["multiselect"]));
|
|
802
893
|
expect(checkbox.checked, "checkbox control").to.be.true;
|
|
894
|
+
expect(propertyCheckbox.checked, "property checkbox control").to.be
|
|
895
|
+
.true;
|
|
896
|
+
expect(propertyInput.value, "property input value").to.be.equal(
|
|
897
|
+
"true",
|
|
898
|
+
);
|
|
899
|
+
expect(propertyCustom.active, "typed property boolean").to.be.true;
|
|
900
|
+
expect(propertyCustom.payload, "typed property object").to.deep.equal(
|
|
901
|
+
{
|
|
902
|
+
state: "ok",
|
|
903
|
+
},
|
|
904
|
+
);
|
|
905
|
+
expect(propertyCustom.getAttribute("active")).to.be.equal(null);
|
|
906
|
+
expect(
|
|
907
|
+
propertyOptionControl.getOption("features.enabled"),
|
|
908
|
+
"control option boolean",
|
|
909
|
+
).to.be.true;
|
|
910
|
+
expect(
|
|
911
|
+
propertyOptionControl.getOption("labels.count"),
|
|
912
|
+
"control option number",
|
|
913
|
+
).to.be.equal(1234);
|
|
803
914
|
|
|
804
915
|
done();
|
|
805
916
|
}, 100);
|