@schukai/monster 3.106.0 → 3.107.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
CHANGED
@@ -2,6 +2,25 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
|
5
|
+
## [3.107.0] - 2025-02-09
|
6
|
+
|
7
|
+
### Add Features
|
8
|
+
|
9
|
+
- **select:** standard value filter function
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
## [3.106.1] - 2025-02-09
|
14
|
+
|
15
|
+
### Bug Fixes
|
16
|
+
|
17
|
+
- **select:** update empty value handling
|
18
|
+
### Changes
|
19
|
+
|
20
|
+
- update nix
|
21
|
+
|
22
|
+
|
23
|
+
|
5
24
|
## [3.106.0] - 2025-02-07
|
6
25
|
|
7
26
|
### Add Features
|
package/package.json
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.13","@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":"3.
|
1
|
+
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.13","@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":"3.107.0"}
|
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
import {instanceSymbol} from "../../constants.mjs";
|
16
16
|
import {internalSymbol} from "../../constants.mjs";
|
17
|
-
import {buildMap} from "../../data/buildmap.mjs";
|
17
|
+
import {buildMap,build as buildValue} from "../../data/buildmap.mjs";
|
18
18
|
import {DeadMansSwitch} from "../../util/deadmansswitch.mjs";
|
19
19
|
import {positionPopper} from "./util/floating-ui.mjs";
|
20
20
|
import {
|
@@ -697,11 +697,12 @@ class Select extends CustomControl {
|
|
697
697
|
* @fires monster-options-set this event is fired when the options are set
|
698
698
|
*/
|
699
699
|
importOptions(data) {
|
700
|
+
const self = this;
|
700
701
|
const mappingOptions = this.getOption("mapping", {});
|
701
702
|
const selector = mappingOptions?.["selector"];
|
702
703
|
const labelTemplate = mappingOptions?.["labelTemplate"];
|
703
704
|
const valueTemplate = mappingOptions?.["valueTemplate"];
|
704
|
-
|
705
|
+
let filter = mappingOptions?.["filter"];
|
705
706
|
|
706
707
|
let flag = false;
|
707
708
|
if (labelTemplate === "") {
|
@@ -717,6 +718,36 @@ class Select extends CustomControl {
|
|
717
718
|
if (flag === true) {
|
718
719
|
throw new Error("missing label configuration");
|
719
720
|
}
|
721
|
+
if (isString(filter) ) {
|
722
|
+
if (0 === filter.indexOf('run:')) {
|
723
|
+
const code = filter.replace('run:', '');
|
724
|
+
filter = (m, v, k) => {
|
725
|
+
const fkt = new Function('m', 'v', 'k', "control", code);
|
726
|
+
return fkt(m, v, k, self);
|
727
|
+
}
|
728
|
+
} else if (0 === filter.indexOf('call:')) {
|
729
|
+
|
730
|
+
const parts = filter.split(':');
|
731
|
+
parts.shift(); // remove prefix
|
732
|
+
const fkt = parts.shift();
|
733
|
+
|
734
|
+
switch (fkt) {
|
735
|
+
case "filterValueOfAttribute":
|
736
|
+
|
737
|
+
const attribute = parts.shift();
|
738
|
+
const attrValue = self.getAttribute(attribute);
|
739
|
+
|
740
|
+
filter = (m, v, k) => {
|
741
|
+
const mm = buildValue(m, valueTemplate);
|
742
|
+
return mm != attrValue; // no type check, no !==
|
743
|
+
}
|
744
|
+
break;
|
745
|
+
|
746
|
+
default:
|
747
|
+
addErrorAttribute(this, new Error(`Unknown filter function ${fkt}`));
|
748
|
+
}
|
749
|
+
}
|
750
|
+
}
|
720
751
|
|
721
752
|
const map = buildMap(data, selector, labelTemplate, valueTemplate, filter);
|
722
753
|
|
@@ -2290,12 +2321,13 @@ function isValueIsEmptyThenGetNormalize(value) {
|
|
2290
2321
|
function setSelection(selection) {
|
2291
2322
|
const self = this;
|
2292
2323
|
|
2324
|
+
selection = isValueIsEmptyThenGetNormalize.call(this, selection);
|
2325
|
+
|
2293
2326
|
if (isString(selection) || isInteger(selection)) {
|
2294
2327
|
const result = convertValueToSelection.call(this, selection);
|
2295
2328
|
selection = result?.selection;
|
2296
2329
|
}
|
2297
2330
|
|
2298
|
-
selection = isValueIsEmptyThenGetNormalize.call(this, selection);
|
2299
2331
|
validateArray(selection);
|
2300
2332
|
|
2301
2333
|
let resultSelection = [];
|
@@ -12,37 +12,38 @@
|
|
12
12
|
* SPDX-License-Identifier: AGPL-3.0
|
13
13
|
*/
|
14
14
|
|
15
|
-
import {
|
15
|
+
import {buildTree} from "../../data/buildtree.mjs";
|
16
16
|
import {
|
17
|
-
|
18
|
-
|
17
|
+
addAttributeToken,
|
18
|
+
findClosestByAttribute,
|
19
19
|
} from "../../dom/attributes.mjs";
|
20
20
|
import {
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
ATTRIBUTE_ERRORMESSAGE,
|
22
|
+
ATTRIBUTE_ROLE,
|
23
|
+
ATTRIBUTE_UPDATER_INSERT_REFERENCE,
|
24
24
|
} from "../../dom/constants.mjs";
|
25
|
-
import {
|
25
|
+
import {instanceSymbol} from "../../constants.mjs";
|
26
26
|
import {
|
27
|
-
|
28
|
-
|
27
|
+
assembleMethodSymbol,
|
28
|
+
registerCustomElement,
|
29
29
|
} from "../../dom/customelement.mjs";
|
30
30
|
import {
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
findTargetElementFromEvent,
|
32
|
+
fireCustomEvent,
|
33
|
+
fireEvent,
|
34
34
|
} from "../../dom/events.mjs";
|
35
|
-
import {
|
36
|
-
import {
|
37
|
-
import {
|
38
|
-
import {
|
39
|
-
import {
|
40
|
-
import {
|
41
|
-
import {
|
42
|
-
import {
|
43
|
-
import {
|
44
|
-
|
45
|
-
|
35
|
+
import {Formatter} from "../../text/formatter.mjs";
|
36
|
+
import {isString} from "../../types/is.mjs";
|
37
|
+
import {Node} from "../../types/node.mjs";
|
38
|
+
import {NodeRecursiveIterator} from "../../types/noderecursiveiterator.mjs";
|
39
|
+
import {validateInstance} from "../../types/validate.mjs";
|
40
|
+
import {ATTRIBUTE_FORM_URL, ATTRIBUTE_INTEND} from "./constants.mjs";
|
41
|
+
import {Select} from "./select.mjs";
|
42
|
+
import {SelectStyleSheet} from "./stylesheet/select.mjs";
|
43
|
+
import {TreeSelectStyleSheet} from "./stylesheet/tree-select.mjs";
|
44
|
+
import {addErrorAttribute} from "../../dom/error.mjs";
|
45
|
+
|
46
|
+
export {TreeSelect, formatHierarchicalSelection};
|
46
47
|
|
47
48
|
/**
|
48
49
|
* @private
|
@@ -72,161 +73,201 @@ const keyEventHandler = Symbol("keyEventHandler");
|
|
72
73
|
* @fires monster-changed
|
73
74
|
*/
|
74
75
|
class TreeSelect extends Select {
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
76
|
+
/**
|
77
|
+
* This method is called by the `instanceof` operator.
|
78
|
+
* @return {symbol}
|
79
|
+
* @since 2.1.0
|
80
|
+
*/
|
81
|
+
static get [instanceSymbol]() {
|
82
|
+
return Symbol.for("@schukai/monster/components/form/tree-select@@instance");
|
83
|
+
}
|
84
|
+
|
85
|
+
/**
|
86
|
+
* To set the options via the HTML tag, the attribute `data-monster-options` must be used.
|
87
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
88
|
+
*
|
89
|
+
* The individual configuration values can be found in the table.
|
90
|
+
*
|
91
|
+
* @extends Select
|
92
|
+
* @property {Array} mapping.rootReferences=['0', undefined, null]
|
93
|
+
* @property {String} mapping.idTemplate=id
|
94
|
+
* @property {String} mapping.parentTemplate=parent
|
95
|
+
* @property {String} mapping.selection
|
96
|
+
* @property {String} mapping.labelTemplate
|
97
|
+
* @property {String} mapping.valueTemplate
|
98
|
+
* @property {String} mapping.filter The filter function to apply to each node, you can use run: syntax to execute a function, or use call:filterValueOfAttribute:data-my-attribute.
|
99
|
+
* @property {Object} formatter
|
100
|
+
* @property {String} formatter.separator=" / "
|
101
|
+
*/
|
102
|
+
get defaults() {
|
103
|
+
return Object.assign(
|
104
|
+
{},
|
105
|
+
super.defaults,
|
106
|
+
{
|
107
|
+
mapping: {
|
108
|
+
rootReferences: ["0", undefined, null],
|
109
|
+
id: "id",
|
110
|
+
parent: "parent",
|
111
|
+
|
112
|
+
selector: "*",
|
113
|
+
labelTemplate: "",
|
114
|
+
valueTemplate: "",
|
115
|
+
|
116
|
+
filter: null,
|
117
|
+
},
|
118
|
+
formatter: {
|
119
|
+
selection: formatHierarchicalSelection,
|
120
|
+
separator: " / ",
|
121
|
+
},
|
122
|
+
templates: {
|
123
|
+
main: getTemplate(),
|
124
|
+
},
|
125
|
+
},
|
126
|
+
initOptionsFromArguments.call(this),
|
127
|
+
);
|
128
|
+
}
|
129
|
+
|
130
|
+
/**
|
131
|
+
*
|
132
|
+
* @return {string}
|
133
|
+
*/
|
134
|
+
static getTag() {
|
135
|
+
return "monster-tree-select";
|
136
|
+
}
|
137
|
+
|
138
|
+
/**
|
139
|
+
*
|
140
|
+
* @return {CSSStyleSheet[]}
|
141
|
+
*/
|
142
|
+
static getCSSStyleSheet() {
|
143
|
+
return [SelectStyleSheet, TreeSelectStyleSheet];
|
144
|
+
}
|
145
|
+
|
146
|
+
/**
|
147
|
+
* Import Select Options from dataset
|
148
|
+
* Not to be confused with the control defaults/options
|
149
|
+
*
|
150
|
+
* @param {array|object|Map|Set} data
|
151
|
+
* @return {Select}
|
152
|
+
* @throws {Error} map is not iterable
|
153
|
+
*/
|
154
|
+
importOptions(data) {
|
155
|
+
const self = this;
|
156
|
+
|
157
|
+
this[internalNodesSymbol] = new Map();
|
158
|
+
|
159
|
+
const id = this.getOption("mapping.id", "id");
|
160
|
+
const parentID = this.getOption("mapping.parent", "parent");
|
161
|
+
|
162
|
+
const mappingOptions = this.getOption("mapping", {});
|
163
|
+
|
164
|
+
let filter = mappingOptions?.["filter"];
|
165
|
+
|
166
|
+
if (isString(filter) ) {
|
167
|
+
if (0 === filter.indexOf('run:')) {
|
168
|
+
const code = filter.replace('run:', '');
|
169
|
+
filter = (m, v, k) => {
|
170
|
+
const fkt = new Function('m', 'v', 'k', "control", code);
|
171
|
+
return fkt(m, v, k, self);
|
172
|
+
}
|
173
|
+
} else if (0 === filter.indexOf('call:')) {
|
174
|
+
|
175
|
+
const parts = filter.split(':');
|
176
|
+
parts.shift(); // remove prefix
|
177
|
+
const fkt = parts.shift();
|
178
|
+
|
179
|
+
switch (fkt) {
|
180
|
+
case "filterValueOfAttribute":
|
181
|
+
|
182
|
+
const attribute = parts.shift();
|
183
|
+
const attrValue = self.getAttribute(attribute);
|
184
|
+
|
185
|
+
filter = (m, v, k) => {
|
186
|
+
return m?.[id] != attrValue; // no type check, no !==
|
187
|
+
}
|
188
|
+
break;
|
189
|
+
|
190
|
+
default:
|
191
|
+
addErrorAttribute(this, new Error(`Unknown filter function ${fkt}`));
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
}
|
196
|
+
|
197
|
+
const rootReferences = mappingOptions?.["rootReferences"];
|
198
|
+
|
199
|
+
const selector = mappingOptions?.["selector"];
|
200
|
+
const options = [];
|
201
|
+
|
202
|
+
try {
|
203
|
+
const nodes = buildTree(data, selector, id, parentID, {
|
204
|
+
filter,
|
205
|
+
rootReferences,
|
206
|
+
});
|
207
|
+
|
208
|
+
for (const node of nodes) {
|
209
|
+
const iterator = new NodeRecursiveIterator(node);
|
210
|
+
for (const n of iterator) {
|
211
|
+
const formattedValues = formatKeyLabel.call(this, n);
|
212
|
+
|
213
|
+
const label = formattedValues.label;
|
214
|
+
const value = formattedValues.value;
|
215
|
+
const intend = n.level;
|
216
|
+
|
217
|
+
const visibility = intend > 0 ? "hidden" : "visible";
|
218
|
+
const state = "close";
|
219
|
+
|
220
|
+
this[internalNodesSymbol].set(value, n);
|
221
|
+
|
222
|
+
options.push({
|
223
|
+
value,
|
224
|
+
label,
|
225
|
+
intend,
|
226
|
+
state,
|
227
|
+
visibility,
|
228
|
+
["has-children"]: n.hasChildNodes(),
|
229
|
+
});
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
this.setOption("options", options);
|
234
|
+
|
235
|
+
fireCustomEvent(this, "monster-options-set", {
|
236
|
+
options,
|
237
|
+
});
|
238
|
+
} catch (e) {
|
239
|
+
addErrorAttribute(this, e);
|
240
|
+
}
|
241
|
+
|
242
|
+
return this;
|
243
|
+
}
|
244
|
+
|
245
|
+
/**
|
246
|
+
*
|
247
|
+
* @return {TreeSelect}
|
248
|
+
*/
|
249
|
+
[assembleMethodSymbol]() {
|
250
|
+
super[assembleMethodSymbol]();
|
251
|
+
initEventHandler.call(this);
|
252
|
+
}
|
213
253
|
}
|
214
254
|
|
255
|
+
|
215
256
|
/**
|
216
257
|
* @private
|
217
258
|
* @param event
|
218
259
|
*/
|
219
260
|
function handleOptionKeyboardEvents(event) {
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
261
|
+
switch (event?.["code"]) {
|
262
|
+
case "ArrowLeft":
|
263
|
+
closeOrOpenCurrentOption.call(this, event, "close");
|
264
|
+
event.preventDefault();
|
265
|
+
break;
|
266
|
+
case "ArrowRight":
|
267
|
+
closeOrOpenCurrentOption.call(this, event, "open");
|
268
|
+
event.preventDefault();
|
269
|
+
break;
|
270
|
+
}
|
230
271
|
}
|
231
272
|
|
232
273
|
/**
|
@@ -234,24 +275,24 @@ function handleOptionKeyboardEvents(event) {
|
|
234
275
|
* @param {event} event
|
235
276
|
*/
|
236
277
|
function closeOrOpenCurrentOption(event, mode) {
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
278
|
+
validateInstance(event, Event);
|
279
|
+
|
280
|
+
if (typeof event.composedPath !== "function") {
|
281
|
+
throw new Error("unsupported event");
|
282
|
+
}
|
283
|
+
|
284
|
+
const path = event.composedPath();
|
285
|
+
const optionNode = path.shift();
|
286
|
+
|
287
|
+
const state = optionNode.getAttribute("data-monster-state");
|
288
|
+
if (state !== mode) {
|
289
|
+
const handler = optionNode.querySelector(
|
290
|
+
"[data-monster-role=folder-handler]",
|
291
|
+
);
|
292
|
+
if (handler instanceof HTMLElement) {
|
293
|
+
fireEvent(handler, "click");
|
294
|
+
}
|
295
|
+
}
|
255
296
|
}
|
256
297
|
|
257
298
|
/**
|
@@ -261,25 +302,25 @@ function closeOrOpenCurrentOption(event, mode) {
|
|
261
302
|
* @private
|
262
303
|
*/
|
263
304
|
function formatKeyLabel(node) {
|
264
|
-
|
305
|
+
validateInstance(node, Node);
|
265
306
|
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
307
|
+
const v = node.value;
|
308
|
+
if (v === undefined) {
|
309
|
+
throw new Error("the object has no value for the specified id");
|
310
|
+
}
|
270
311
|
|
271
|
-
|
272
|
-
|
273
|
-
|
312
|
+
const label = new Formatter(v).format(
|
313
|
+
this.getOption("mapping.labelTemplate", ""),
|
314
|
+
);
|
274
315
|
|
275
|
-
|
276
|
-
|
277
|
-
|
316
|
+
const value = new Formatter(v).format(
|
317
|
+
this.getOption("mapping.valueTemplate", ""),
|
318
|
+
);
|
278
319
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
320
|
+
return {
|
321
|
+
value,
|
322
|
+
label,
|
323
|
+
};
|
283
324
|
}
|
284
325
|
|
285
326
|
/**
|
@@ -288,27 +329,27 @@ function formatKeyLabel(node) {
|
|
288
329
|
* @return {Array}
|
289
330
|
*/
|
290
331
|
function buildTreeLabels(value) {
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
332
|
+
if (!this[internalNodesSymbol]) {
|
333
|
+
return [value];
|
334
|
+
}
|
335
|
+
|
336
|
+
let node = this[internalNodesSymbol].get(value);
|
337
|
+
if (node === undefined) {
|
338
|
+
node = this[internalNodesSymbol].get(parseInt(value));
|
339
|
+
}
|
340
|
+
|
341
|
+
const parts = [];
|
342
|
+
|
343
|
+
if (node instanceof Node) {
|
344
|
+
let ptr = node;
|
345
|
+
while (ptr) {
|
346
|
+
const formattedValues = formatKeyLabel.call(this, ptr);
|
347
|
+
parts.unshift(formattedValues.label);
|
348
|
+
ptr = ptr.parent;
|
349
|
+
}
|
350
|
+
}
|
351
|
+
|
352
|
+
return parts;
|
312
353
|
}
|
313
354
|
|
314
355
|
/**
|
@@ -326,9 +367,9 @@ function buildTreeLabels(value) {
|
|
326
367
|
* @return {string}
|
327
368
|
*/
|
328
369
|
function formatHierarchicalSelection(value) {
|
329
|
-
|
330
|
-
|
331
|
-
|
370
|
+
return buildTreeLabels
|
371
|
+
.call(this, value)
|
372
|
+
.join(this.getOption("formatter.separator", " / "));
|
332
373
|
}
|
333
374
|
|
334
375
|
/**
|
@@ -342,99 +383,99 @@ const openOptionEventHandler = Symbol("openOptionEventHandler");
|
|
342
383
|
* @throws {Error} no shadow-root is defined
|
343
384
|
*/
|
344
385
|
function initEventHandler() {
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
386
|
+
if (!this.shadowRoot) {
|
387
|
+
throw new Error("no shadow-root is defined");
|
388
|
+
}
|
389
|
+
|
390
|
+
this[openOptionEventHandler] = (event) => {
|
391
|
+
const element = findTargetElementFromEvent(
|
392
|
+
event,
|
393
|
+
ATTRIBUTE_ROLE,
|
394
|
+
"folder-handler",
|
395
|
+
);
|
396
|
+
if (!(element instanceof HTMLElement)) {
|
397
|
+
return;
|
398
|
+
}
|
399
|
+
|
400
|
+
const container = findClosestByAttribute(element, ATTRIBUTE_ROLE, "option");
|
401
|
+
const index = container
|
402
|
+
.getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE)
|
403
|
+
.split("-")
|
404
|
+
.pop();
|
405
|
+
|
406
|
+
const currentState = this.getOption(`options.${index}.state`);
|
407
|
+
|
408
|
+
const newState = currentState === "close" ? "open" : "close";
|
409
|
+
this.setOption(`options.${index}.state`, newState);
|
410
|
+
|
411
|
+
const newVisibility = newState === "open" ? "visible" : "hidden";
|
412
|
+
|
413
|
+
if (container.hasAttribute(ATTRIBUTE_INTEND)) {
|
414
|
+
const intend = container.getAttribute(ATTRIBUTE_INTEND);
|
415
|
+
|
416
|
+
let ref = container.nextElementSibling;
|
417
|
+
const childIntend = parseInt(intend) + 1;
|
418
|
+
|
419
|
+
const cmp = (a, b) => {
|
420
|
+
if (newState === "open") {
|
421
|
+
return a === b;
|
422
|
+
}
|
423
|
+
|
424
|
+
return a >= b;
|
425
|
+
};
|
426
|
+
|
427
|
+
while (
|
428
|
+
ref?.hasAttribute(ATTRIBUTE_INTEND) &&
|
429
|
+
cmp(parseInt(ref.getAttribute(ATTRIBUTE_INTEND)), childIntend)
|
430
|
+
) {
|
431
|
+
const refIndex = ref
|
432
|
+
.getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE)
|
433
|
+
.split("-")
|
434
|
+
.pop();
|
435
|
+
this.setOption(`options.${refIndex}.visibility`, newVisibility);
|
436
|
+
|
437
|
+
if (newState === "close") {
|
438
|
+
this.setOption(`options.${refIndex}.state`, "close");
|
439
|
+
}
|
440
|
+
|
441
|
+
ref = ref.nextElementSibling;
|
442
|
+
}
|
443
|
+
}
|
444
|
+
};
|
445
|
+
|
446
|
+
this[keyEventHandler] = (event) => {
|
447
|
+
const path = event.composedPath();
|
448
|
+
const element = path?.[0];
|
449
|
+
|
450
|
+
let role;
|
451
|
+
|
452
|
+
if (element instanceof HTMLElement) {
|
453
|
+
if (element.hasAttribute(ATTRIBUTE_ROLE)) {
|
454
|
+
role = element.getAttribute(ATTRIBUTE_ROLE);
|
455
|
+
} else if (element === this) {
|
456
|
+
show.call(this);
|
457
|
+
focusFilter.call(this);
|
458
|
+
} else {
|
459
|
+
const e = element.closest(`[${ATTRIBUTE_ROLE}]`);
|
460
|
+
if (e instanceof HTMLElement && e.hasAttribute()) {
|
461
|
+
role = e.getAttribute(ATTRIBUTE_ROLE);
|
462
|
+
}
|
463
|
+
}
|
464
|
+
} else {
|
465
|
+
return;
|
466
|
+
}
|
467
|
+
|
468
|
+
switch (role) {
|
469
|
+
case "option-label":
|
470
|
+
case "option-control":
|
471
|
+
case "option":
|
472
|
+
handleOptionKeyboardEvents.call(this, event);
|
473
|
+
break;
|
474
|
+
}
|
475
|
+
};
|
476
|
+
|
477
|
+
this.shadowRoot.addEventListener("keydown", this[keyEventHandler]);
|
478
|
+
this.shadowRoot.addEventListener("click", this[openOptionEventHandler]);
|
438
479
|
}
|
439
480
|
|
440
481
|
/**
|
@@ -448,14 +489,14 @@ function initEventHandler() {
|
|
448
489
|
* @return {object}
|
449
490
|
*/
|
450
491
|
function initOptionsFromArguments() {
|
451
|
-
|
492
|
+
const options = {};
|
452
493
|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
494
|
+
const url = this.getAttribute(ATTRIBUTE_FORM_URL);
|
495
|
+
if (isString(url)) {
|
496
|
+
options["url"] = new URL(url).toString();
|
497
|
+
}
|
457
498
|
|
458
|
-
|
499
|
+
return options;
|
459
500
|
}
|
460
501
|
|
461
502
|
/**
|
@@ -463,8 +504,8 @@ function initOptionsFromArguments() {
|
|
463
504
|
* @return {string}
|
464
505
|
*/
|
465
506
|
function getTemplate() {
|
466
|
-
|
467
|
-
|
507
|
+
// language=HTML
|
508
|
+
return `
|
468
509
|
<template id="options">
|
469
510
|
<div data-monster-role="option"
|
470
511
|
tabindex="-1"
|
package/source/data/buildmap.mjs
CHANGED
@@ -17,7 +17,7 @@ import { validateString } from "../types/validate.mjs";
|
|
17
17
|
import { clone } from "../util/clone.mjs";
|
18
18
|
import { DELIMITER, Pathfinder, WILDCARD } from "./pathfinder.mjs";
|
19
19
|
|
20
|
-
export { buildMap, PARENT, assembleParts
|
20
|
+
export { buildMap, PARENT, assembleParts};
|
21
21
|
|
22
22
|
/**
|
23
23
|
* @type {string}
|
@@ -361,7 +361,7 @@ function buildFlatMap(subject, selector, key, parentMap) {
|
|
361
361
|
* @param {*} defaultValue
|
362
362
|
* @return {*}
|
363
363
|
*/
|
364
|
-
function build(subject, definition, defaultValue) {
|
364
|
+
export function build(subject, definition, defaultValue) {
|
365
365
|
if (definition === undefined) return defaultValue ? defaultValue : subject;
|
366
366
|
validateString(definition);
|
367
367
|
|
package/source/dom/updater.mjs
CHANGED