@schukai/monster 3.107.0 → 3.108.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 +21 -10
- package/source/components/datatable/save-button.mjs +8 -10
- package/source/components/form/select.mjs +2236 -2248
- package/source/components/form/tree-select.mjs +369 -370
- package/source/data/buildmap.mjs +1 -1
- package/source/data/datasource/server/restapi.mjs +3 -3
- package/source/data/transformer.mjs +34 -1
- package/source/dom/updater.mjs +858 -854
- package/source/i18n/internal.mjs +103 -109
- package/source/i18n/map/languages.mjs +1 -3
- package/source/monster.mjs +1 -0
- package/source/types/global.mjs +45 -46
- 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 +478 -149
@@ -12,38 +12,38 @@
|
|
12
12
|
* SPDX-License-Identifier: AGPL-3.0
|
13
13
|
*/
|
14
14
|
|
15
|
-
import {buildTree} from "../../data/buildtree.mjs";
|
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 {instanceSymbol} from "../../constants.mjs";
|
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 {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};
|
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 };
|
47
47
|
|
48
48
|
/**
|
49
49
|
* @private
|
@@ -73,201 +73,200 @@ const keyEventHandler = Symbol("keyEventHandler");
|
|
73
73
|
* @fires monster-changed
|
74
74
|
*/
|
75
75
|
class TreeSelect extends Select {
|
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
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
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
|
+
const parts = filter.split(":");
|
175
|
+
parts.shift(); // remove prefix
|
176
|
+
const fkt = parts.shift();
|
177
|
+
|
178
|
+
switch (fkt) {
|
179
|
+
case "filterValueOfAttribute":
|
180
|
+
const attribute = parts.shift();
|
181
|
+
const attrValue = self.getAttribute(attribute);
|
182
|
+
|
183
|
+
filter = (m, v, k) => {
|
184
|
+
return m?.[id] != attrValue; // no type check, no !==
|
185
|
+
};
|
186
|
+
break;
|
187
|
+
|
188
|
+
default:
|
189
|
+
addErrorAttribute(
|
190
|
+
this,
|
191
|
+
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
|
+
}
|
253
253
|
}
|
254
254
|
|
255
|
-
|
256
255
|
/**
|
257
256
|
* @private
|
258
257
|
* @param event
|
259
258
|
*/
|
260
259
|
function handleOptionKeyboardEvents(event) {
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
260
|
+
switch (event?.["code"]) {
|
261
|
+
case "ArrowLeft":
|
262
|
+
closeOrOpenCurrentOption.call(this, event, "close");
|
263
|
+
event.preventDefault();
|
264
|
+
break;
|
265
|
+
case "ArrowRight":
|
266
|
+
closeOrOpenCurrentOption.call(this, event, "open");
|
267
|
+
event.preventDefault();
|
268
|
+
break;
|
269
|
+
}
|
271
270
|
}
|
272
271
|
|
273
272
|
/**
|
@@ -275,24 +274,24 @@ function handleOptionKeyboardEvents(event) {
|
|
275
274
|
* @param {event} event
|
276
275
|
*/
|
277
276
|
function closeOrOpenCurrentOption(event, mode) {
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
277
|
+
validateInstance(event, Event);
|
278
|
+
|
279
|
+
if (typeof event.composedPath !== "function") {
|
280
|
+
throw new Error("unsupported event");
|
281
|
+
}
|
282
|
+
|
283
|
+
const path = event.composedPath();
|
284
|
+
const optionNode = path.shift();
|
285
|
+
|
286
|
+
const state = optionNode.getAttribute("data-monster-state");
|
287
|
+
if (state !== mode) {
|
288
|
+
const handler = optionNode.querySelector(
|
289
|
+
"[data-monster-role=folder-handler]",
|
290
|
+
);
|
291
|
+
if (handler instanceof HTMLElement) {
|
292
|
+
fireEvent(handler, "click");
|
293
|
+
}
|
294
|
+
}
|
296
295
|
}
|
297
296
|
|
298
297
|
/**
|
@@ -302,25 +301,25 @@ function closeOrOpenCurrentOption(event, mode) {
|
|
302
301
|
* @private
|
303
302
|
*/
|
304
303
|
function formatKeyLabel(node) {
|
305
|
-
|
304
|
+
validateInstance(node, Node);
|
306
305
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
306
|
+
const v = node.value;
|
307
|
+
if (v === undefined) {
|
308
|
+
throw new Error("the object has no value for the specified id");
|
309
|
+
}
|
311
310
|
|
312
|
-
|
313
|
-
|
314
|
-
|
311
|
+
const label = new Formatter(v).format(
|
312
|
+
this.getOption("mapping.labelTemplate", ""),
|
313
|
+
);
|
315
314
|
|
316
|
-
|
317
|
-
|
318
|
-
|
315
|
+
const value = new Formatter(v).format(
|
316
|
+
this.getOption("mapping.valueTemplate", ""),
|
317
|
+
);
|
319
318
|
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
319
|
+
return {
|
320
|
+
value,
|
321
|
+
label,
|
322
|
+
};
|
324
323
|
}
|
325
324
|
|
326
325
|
/**
|
@@ -329,27 +328,27 @@ function formatKeyLabel(node) {
|
|
329
328
|
* @return {Array}
|
330
329
|
*/
|
331
330
|
function buildTreeLabels(value) {
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
331
|
+
if (!this[internalNodesSymbol]) {
|
332
|
+
return [value];
|
333
|
+
}
|
334
|
+
|
335
|
+
let node = this[internalNodesSymbol].get(value);
|
336
|
+
if (node === undefined) {
|
337
|
+
node = this[internalNodesSymbol].get(parseInt(value));
|
338
|
+
}
|
339
|
+
|
340
|
+
const parts = [];
|
341
|
+
|
342
|
+
if (node instanceof Node) {
|
343
|
+
let ptr = node;
|
344
|
+
while (ptr) {
|
345
|
+
const formattedValues = formatKeyLabel.call(this, ptr);
|
346
|
+
parts.unshift(formattedValues.label);
|
347
|
+
ptr = ptr.parent;
|
348
|
+
}
|
349
|
+
}
|
350
|
+
|
351
|
+
return parts;
|
353
352
|
}
|
354
353
|
|
355
354
|
/**
|
@@ -367,9 +366,9 @@ function buildTreeLabels(value) {
|
|
367
366
|
* @return {string}
|
368
367
|
*/
|
369
368
|
function formatHierarchicalSelection(value) {
|
370
|
-
|
371
|
-
|
372
|
-
|
369
|
+
return buildTreeLabels
|
370
|
+
.call(this, value)
|
371
|
+
.join(this.getOption("formatter.separator", " / "));
|
373
372
|
}
|
374
373
|
|
375
374
|
/**
|
@@ -383,99 +382,99 @@ const openOptionEventHandler = Symbol("openOptionEventHandler");
|
|
383
382
|
* @throws {Error} no shadow-root is defined
|
384
383
|
*/
|
385
384
|
function initEventHandler() {
|
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
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
385
|
+
if (!this.shadowRoot) {
|
386
|
+
throw new Error("no shadow-root is defined");
|
387
|
+
}
|
388
|
+
|
389
|
+
this[openOptionEventHandler] = (event) => {
|
390
|
+
const element = findTargetElementFromEvent(
|
391
|
+
event,
|
392
|
+
ATTRIBUTE_ROLE,
|
393
|
+
"folder-handler",
|
394
|
+
);
|
395
|
+
if (!(element instanceof HTMLElement)) {
|
396
|
+
return;
|
397
|
+
}
|
398
|
+
|
399
|
+
const container = findClosestByAttribute(element, ATTRIBUTE_ROLE, "option");
|
400
|
+
const index = container
|
401
|
+
.getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE)
|
402
|
+
.split("-")
|
403
|
+
.pop();
|
404
|
+
|
405
|
+
const currentState = this.getOption(`options.${index}.state`);
|
406
|
+
|
407
|
+
const newState = currentState === "close" ? "open" : "close";
|
408
|
+
this.setOption(`options.${index}.state`, newState);
|
409
|
+
|
410
|
+
const newVisibility = newState === "open" ? "visible" : "hidden";
|
411
|
+
|
412
|
+
if (container.hasAttribute(ATTRIBUTE_INTEND)) {
|
413
|
+
const intend = container.getAttribute(ATTRIBUTE_INTEND);
|
414
|
+
|
415
|
+
let ref = container.nextElementSibling;
|
416
|
+
const childIntend = parseInt(intend) + 1;
|
417
|
+
|
418
|
+
const cmp = (a, b) => {
|
419
|
+
if (newState === "open") {
|
420
|
+
return a === b;
|
421
|
+
}
|
422
|
+
|
423
|
+
return a >= b;
|
424
|
+
};
|
425
|
+
|
426
|
+
while (
|
427
|
+
ref?.hasAttribute(ATTRIBUTE_INTEND) &&
|
428
|
+
cmp(parseInt(ref.getAttribute(ATTRIBUTE_INTEND)), childIntend)
|
429
|
+
) {
|
430
|
+
const refIndex = ref
|
431
|
+
.getAttribute(ATTRIBUTE_UPDATER_INSERT_REFERENCE)
|
432
|
+
.split("-")
|
433
|
+
.pop();
|
434
|
+
this.setOption(`options.${refIndex}.visibility`, newVisibility);
|
435
|
+
|
436
|
+
if (newState === "close") {
|
437
|
+
this.setOption(`options.${refIndex}.state`, "close");
|
438
|
+
}
|
439
|
+
|
440
|
+
ref = ref.nextElementSibling;
|
441
|
+
}
|
442
|
+
}
|
443
|
+
};
|
444
|
+
|
445
|
+
this[keyEventHandler] = (event) => {
|
446
|
+
const path = event.composedPath();
|
447
|
+
const element = path?.[0];
|
448
|
+
|
449
|
+
let role;
|
450
|
+
|
451
|
+
if (element instanceof HTMLElement) {
|
452
|
+
if (element.hasAttribute(ATTRIBUTE_ROLE)) {
|
453
|
+
role = element.getAttribute(ATTRIBUTE_ROLE);
|
454
|
+
} else if (element === this) {
|
455
|
+
show.call(this);
|
456
|
+
focusFilter.call(this);
|
457
|
+
} else {
|
458
|
+
const e = element.closest(`[${ATTRIBUTE_ROLE}]`);
|
459
|
+
if (e instanceof HTMLElement && e.hasAttribute()) {
|
460
|
+
role = e.getAttribute(ATTRIBUTE_ROLE);
|
461
|
+
}
|
462
|
+
}
|
463
|
+
} else {
|
464
|
+
return;
|
465
|
+
}
|
466
|
+
|
467
|
+
switch (role) {
|
468
|
+
case "option-label":
|
469
|
+
case "option-control":
|
470
|
+
case "option":
|
471
|
+
handleOptionKeyboardEvents.call(this, event);
|
472
|
+
break;
|
473
|
+
}
|
474
|
+
};
|
475
|
+
|
476
|
+
this.shadowRoot.addEventListener("keydown", this[keyEventHandler]);
|
477
|
+
this.shadowRoot.addEventListener("click", this[openOptionEventHandler]);
|
479
478
|
}
|
480
479
|
|
481
480
|
/**
|
@@ -489,14 +488,14 @@ function initEventHandler() {
|
|
489
488
|
* @return {object}
|
490
489
|
*/
|
491
490
|
function initOptionsFromArguments() {
|
492
|
-
|
491
|
+
const options = {};
|
493
492
|
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
493
|
+
const url = this.getAttribute(ATTRIBUTE_FORM_URL);
|
494
|
+
if (isString(url)) {
|
495
|
+
options["url"] = new URL(url).toString();
|
496
|
+
}
|
498
497
|
|
499
|
-
|
498
|
+
return options;
|
500
499
|
}
|
501
500
|
|
502
501
|
/**
|
@@ -504,8 +503,8 @@ function initOptionsFromArguments() {
|
|
504
503
|
* @return {string}
|
505
504
|
*/
|
506
505
|
function getTemplate() {
|
507
|
-
|
508
|
-
|
506
|
+
// language=HTML
|
507
|
+
return `
|
509
508
|
<template id="options">
|
510
509
|
<div data-monster-role="option"
|
511
510
|
tabindex="-1"
|