@schukai/monster 4.143.3 → 4.143.5
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/package.json +1 -1
- package/source/components/datatable/filter.mjs +8 -0
- package/source/components/form/control-bar.mjs +7 -1
- package/source/text/bracketed-key-value-hash.mjs +25 -0
- package/test/cases/components/form/control-bar.mjs +88 -0
- package/test/cases/text/bracketed-key-value-hash.mjs +22 -0
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"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.143.
|
|
1
|
+
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"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.143.5"}
|
|
@@ -1089,6 +1089,10 @@ function initTabEvents() {
|
|
|
1089
1089
|
return host.getConfig(configKey);
|
|
1090
1090
|
})
|
|
1091
1091
|
.then((config) => {
|
|
1092
|
+
if (!isObject(config)) {
|
|
1093
|
+
return;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1092
1096
|
for (const [name, query] of Object.entries(config)) {
|
|
1093
1097
|
if (labels.includes(name)) {
|
|
1094
1098
|
continue;
|
|
@@ -1130,6 +1134,10 @@ function updateFilterTabs() {
|
|
|
1130
1134
|
return host.getConfig(configKey);
|
|
1131
1135
|
})
|
|
1132
1136
|
.then((config) => {
|
|
1137
|
+
if (!isObject(config)) {
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1133
1141
|
for (const [name, query] of Object.entries(config)) {
|
|
1134
1142
|
const found = element.querySelector(
|
|
1135
1143
|
`[data-monster-button-label="${name}"]`,
|
|
@@ -1396,7 +1396,13 @@ function getVisualBorderElement(element, side) {
|
|
|
1396
1396
|
"[data-monster-role=control]",
|
|
1397
1397
|
].join(",");
|
|
1398
1398
|
if (element.shadowRoot instanceof ShadowRoot) {
|
|
1399
|
-
return
|
|
1399
|
+
return (
|
|
1400
|
+
element.shadowRoot.querySelector("button,input,select,textarea") ||
|
|
1401
|
+
element.shadowRoot.querySelector(
|
|
1402
|
+
"monster-input-group,monster-select,[data-monster-role=control]",
|
|
1403
|
+
) ||
|
|
1404
|
+
element
|
|
1405
|
+
);
|
|
1400
1406
|
}
|
|
1401
1407
|
|
|
1402
1408
|
const candidates = Array.from(element.querySelectorAll(selector)).filter(
|
|
@@ -82,6 +82,8 @@ function parseBracketedKeyValueHash(hashString) {
|
|
|
82
82
|
let inSelector = true;
|
|
83
83
|
let escaped = false;
|
|
84
84
|
let quotedValueStartChar = "";
|
|
85
|
+
let valueParenthesisDepth = 0;
|
|
86
|
+
let valueClosedByParenthesis = false;
|
|
85
87
|
|
|
86
88
|
for (let i = 0; i < cleanedHashString.length; i++) {
|
|
87
89
|
const c = cleanedHashString[i];
|
|
@@ -166,6 +168,19 @@ function parseBracketedKeyValueHash(hashString) {
|
|
|
166
168
|
continue;
|
|
167
169
|
}
|
|
168
170
|
|
|
171
|
+
if (c === "(") {
|
|
172
|
+
valueParenthesisDepth++;
|
|
173
|
+
currentValue += c;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (c === ")" && valueParenthesisDepth > 0) {
|
|
178
|
+
valueParenthesisDepth--;
|
|
179
|
+
currentValue += c;
|
|
180
|
+
valueClosedByParenthesis = valueParenthesisDepth === 0;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
169
184
|
if (c === ",") {
|
|
170
185
|
inValue = false;
|
|
171
186
|
inKey = true;
|
|
@@ -173,6 +188,8 @@ function parseBracketedKeyValueHash(hashString) {
|
|
|
173
188
|
addToResult(currentKey, decodedCurrentValue);
|
|
174
189
|
currentKey = "";
|
|
175
190
|
currentValue = "";
|
|
191
|
+
valueParenthesisDepth = 0;
|
|
192
|
+
valueClosedByParenthesis = false;
|
|
176
193
|
continue;
|
|
177
194
|
}
|
|
178
195
|
|
|
@@ -186,6 +203,8 @@ function parseBracketedKeyValueHash(hashString) {
|
|
|
186
203
|
currentKey = "";
|
|
187
204
|
currentValue = "";
|
|
188
205
|
currentSelector = "";
|
|
206
|
+
valueParenthesisDepth = 0;
|
|
207
|
+
valueClosedByParenthesis = false;
|
|
189
208
|
continue;
|
|
190
209
|
}
|
|
191
210
|
|
|
@@ -199,6 +218,12 @@ function parseBracketedKeyValueHash(hashString) {
|
|
|
199
218
|
return selectors;
|
|
200
219
|
}
|
|
201
220
|
|
|
221
|
+
if (inValue && valueParenthesisDepth === 0 && valueClosedByParenthesis) {
|
|
222
|
+
const decodedCurrentValue = decodeURIComponent(currentValue);
|
|
223
|
+
addToResult(currentKey, decodedCurrentValue);
|
|
224
|
+
return selectors;
|
|
225
|
+
}
|
|
226
|
+
|
|
202
227
|
return {};
|
|
203
228
|
}
|
|
204
229
|
|
|
@@ -30,6 +30,8 @@ describe("ControlBar", function () {
|
|
|
30
30
|
Promise.all([
|
|
31
31
|
import("../../../../source/components/form/control-bar.mjs"),
|
|
32
32
|
import("../../../../source/components/form/control-bar-spacer.mjs"),
|
|
33
|
+
import("../../../../source/components/form/button.mjs"),
|
|
34
|
+
import("../../../../source/components/form/popper-button.mjs"),
|
|
33
35
|
])
|
|
34
36
|
.then((m) => {
|
|
35
37
|
ControlBar = m[0].ControlBar;
|
|
@@ -380,6 +382,92 @@ describe("ControlBar", function () {
|
|
|
380
382
|
}
|
|
381
383
|
});
|
|
382
384
|
|
|
385
|
+
it("should join borders between direct monster button controls", async function () {
|
|
386
|
+
const originalRequestAnimationFrame = window.requestAnimationFrame;
|
|
387
|
+
const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
|
|
388
|
+
|
|
389
|
+
const scheduledCallbacks = [];
|
|
390
|
+
const flushFrames = async () => {
|
|
391
|
+
while (scheduledCallbacks.length > 0) {
|
|
392
|
+
scheduledCallbacks.shift()();
|
|
393
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
window.requestAnimationFrame = (callback) => {
|
|
399
|
+
scheduledCallbacks.push(callback);
|
|
400
|
+
return scheduledCallbacks.length;
|
|
401
|
+
};
|
|
402
|
+
globalThis.requestAnimationFrame = window.requestAnimationFrame;
|
|
403
|
+
|
|
404
|
+
const mocks = document.getElementById("mocks");
|
|
405
|
+
mocks.innerHTML = `
|
|
406
|
+
<div id="monster-button-border-bar-wrapper">
|
|
407
|
+
<monster-control-bar id="monster-button-border-bar">
|
|
408
|
+
<monster-popper-button id="monster-button-border-create">
|
|
409
|
+
<span slot="button">Create</span>
|
|
410
|
+
</monster-popper-button>
|
|
411
|
+
<monster-button id="monster-button-border-tags">Manage tags</monster-button>
|
|
412
|
+
<monster-button id="monster-button-border-import">Import</monster-button>
|
|
413
|
+
</monster-control-bar>
|
|
414
|
+
</div>
|
|
415
|
+
`;
|
|
416
|
+
|
|
417
|
+
const wrapper = document.getElementById(
|
|
418
|
+
"monster-button-border-bar-wrapper",
|
|
419
|
+
);
|
|
420
|
+
const controls = [
|
|
421
|
+
document.getElementById("monster-button-border-create"),
|
|
422
|
+
document.getElementById("monster-button-border-tags"),
|
|
423
|
+
document.getElementById("monster-button-border-import"),
|
|
424
|
+
];
|
|
425
|
+
|
|
426
|
+
wrapper.style.boxSizing = "border-box";
|
|
427
|
+
wrapper.style.width = "400px";
|
|
428
|
+
Object.defineProperty(wrapper, "clientWidth", {
|
|
429
|
+
configurable: true,
|
|
430
|
+
value: 400,
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
for (const control of controls) {
|
|
434
|
+
Object.defineProperty(control, "offsetWidth", {
|
|
435
|
+
configurable: true,
|
|
436
|
+
value: 80,
|
|
437
|
+
});
|
|
438
|
+
Object.defineProperty(control, "offsetHeight", {
|
|
439
|
+
configurable: true,
|
|
440
|
+
value: 30,
|
|
441
|
+
});
|
|
442
|
+
control.getBoundingClientRect = () => ({
|
|
443
|
+
width: 80,
|
|
444
|
+
height: 30,
|
|
445
|
+
top: 0,
|
|
446
|
+
right: 80,
|
|
447
|
+
bottom: 30,
|
|
448
|
+
left: 0,
|
|
449
|
+
x: 0,
|
|
450
|
+
y: 0,
|
|
451
|
+
toJSON: () => {},
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
const innerButton = control.shadowRoot?.querySelector("button");
|
|
455
|
+
innerButton.style.borderLeftWidth = "3px";
|
|
456
|
+
innerButton.style.borderRightWidth = "3px";
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
await flushFrames();
|
|
460
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
461
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
462
|
+
|
|
463
|
+
expect(controls[1].style.marginLeft).to.equal("-3px");
|
|
464
|
+
expect(controls[2].style.marginLeft).to.equal("-3px");
|
|
465
|
+
} finally {
|
|
466
|
+
window.requestAnimationFrame = originalRequestAnimationFrame;
|
|
467
|
+
globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
|
|
383
471
|
it("should size inline spacer lines from adjacent border widths", async function () {
|
|
384
472
|
const originalRequestAnimationFrame = window.requestAnimationFrame;
|
|
385
473
|
const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
|
|
@@ -106,6 +106,16 @@ describe("parseBracketedKeyValueHash", () => {
|
|
|
106
106
|
expect(result).to.deep.equal({selector: {key1: 'value,1', key2: 'value,2'}});
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
+
it('should keep unencoded parentheses inside a percent-encoded filter expression', () => {
|
|
110
|
+
const hashString = '#list-filter-nucleus-pim-product-variants-list(tags=tags%20IN%20(%22gustav-varianten%22)';
|
|
111
|
+
const result = parseBracketedKeyValueHash(hashString);
|
|
112
|
+
expect(result).to.deep.equal({
|
|
113
|
+
'list-filter-nucleus-pim-product-variants-list': {
|
|
114
|
+
tags: 'tags IN ("gustav-varianten")'
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
109
119
|
it('should ignore leading hash symbol (#)', () => {
|
|
110
120
|
const hashString = 'selector(key=value)';
|
|
111
121
|
const result = parseBracketedKeyValueHash(hashString);
|
|
@@ -195,6 +205,18 @@ describe("parseBracketedKeyValueHash", () => {
|
|
|
195
205
|
const result = createBracketedKeyValueHash(input, true);
|
|
196
206
|
expect(result).to.deep.equal("#.example(color=r%22ed,font-size=14px);.other(background=blue)");
|
|
197
207
|
});
|
|
208
|
+
|
|
209
|
+
it('should round-trip a filter expression with quotes and parentheses', () => {
|
|
210
|
+
const input = {
|
|
211
|
+
'list-filter-nucleus-pim-product-variants-list': {
|
|
212
|
+
tags: 'tags IN ("gustav-varianten")'
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const hashString = createBracketedKeyValueHash(input, true);
|
|
217
|
+
const result = parseBracketedKeyValueHash(hashString);
|
|
218
|
+
expect(result).to.deep.equal(input);
|
|
219
|
+
});
|
|
198
220
|
|
|
199
221
|
it('should return an empty string for an empty object', () => {
|
|
200
222
|
const input = {};
|