@schukai/monster 3.100.5 → 3.100.7

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.
Files changed (30) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/package.json +1 -1
  3. package/source/components/datatable/dataset.mjs +10 -5
  4. package/source/components/datatable/datasource.mjs +0 -1
  5. package/source/components/datatable/datatable.mjs +2 -0
  6. package/source/components/datatable/filter.mjs +4 -5
  7. package/source/components/datatable/style/datatable.pcss +1 -1
  8. package/source/components/datatable/util.mjs +2 -2
  9. package/source/components/form/api-bar.mjs +1 -1
  10. package/source/components/form/api-button.mjs +1 -1
  11. package/source/components/form/button.mjs +21 -1
  12. package/source/components/form/confirm-button.mjs +0 -45
  13. package/source/components/form/context-help.mjs +1 -1
  14. package/source/components/form/form.mjs +165 -164
  15. package/source/components/form/message-state-button.mjs +21 -7
  16. package/source/components/form/popper-button.mjs +25 -57
  17. package/source/components/form/select.mjs +2142 -2164
  18. package/source/components/form/state-button.mjs +24 -14
  19. package/source/components/form/style/button.pcss +2 -0
  20. package/source/components/form/style/message-state-button.pcss +1 -2
  21. package/source/components/form/style/state-button.pcss +1 -0
  22. package/source/components/form/stylesheet/button.mjs +1 -1
  23. package/source/components/form/stylesheet/field-set.mjs +14 -7
  24. package/source/components/form/stylesheet/message-state-button.mjs +7 -14
  25. package/source/components/form/stylesheet/state-button.mjs +7 -14
  26. package/source/components/layout/collapse.mjs +1 -1
  27. package/source/components/layout/details.mjs +1 -1
  28. package/source/components/style/accessibility.css +27 -0
  29. package/source/components/style/accessibility.pcss +31 -0
  30. package/source/components/stylesheet/accessibility.mjs +38 -0
@@ -12,62 +12,59 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import {instanceSymbol} from "../../constants.mjs";
16
- import {internalSymbol} from "../../constants.mjs";
17
- import {buildMap} from "../../data/buildmap.mjs";
18
- import {DeadMansSwitch} from "../../util/deadmansswitch.mjs";
19
- import {positionPopper} from "./util/floating-ui.mjs";
15
+ import { instanceSymbol } from "../../constants.mjs";
16
+ import { internalSymbol } from "../../constants.mjs";
17
+ import { buildMap } from "../../data/buildmap.mjs";
18
+ import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
19
+ import { positionPopper } from "./util/floating-ui.mjs";
20
20
  import {
21
- addAttributeToken,
22
- findClosestByAttribute,
23
- removeAttributeToken,
21
+ addAttributeToken,
22
+ findClosestByAttribute,
23
+ removeAttributeToken,
24
24
  } from "../../dom/attributes.mjs";
25
+ import { ATTRIBUTE_PREFIX, ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
26
+ import { CustomControl } from "../../dom/customcontrol.mjs";
25
27
  import {
26
- ATTRIBUTE_PREFIX,
27
- ATTRIBUTE_ROLE,
28
- } from "../../dom/constants.mjs";
29
- import {CustomControl} from "../../dom/customcontrol.mjs";
30
- import {
31
- assembleMethodSymbol,
32
- getSlottedElements,
33
- registerCustomElement,
28
+ assembleMethodSymbol,
29
+ getSlottedElements,
30
+ registerCustomElement,
34
31
  } from "../../dom/customelement.mjs";
35
32
  import {
36
- findTargetElementFromEvent,
37
- fireCustomEvent,
38
- fireEvent,
33
+ findTargetElementFromEvent,
34
+ fireCustomEvent,
35
+ fireEvent,
39
36
  } from "../../dom/events.mjs";
40
- import {getDocument} from "../../dom/util.mjs";
41
- import {Formatter} from "../../text/formatter.mjs";
42
- import {getGlobal} from "../../types/global.mjs";
43
- import {ID} from "../../types/id.mjs";
37
+ import { getDocument } from "../../dom/util.mjs";
38
+ import { Formatter } from "../../text/formatter.mjs";
39
+ import { getGlobal } from "../../types/global.mjs";
40
+ import { ID } from "../../types/id.mjs";
44
41
  import {
45
- isArray,
46
- isFunction,
47
- isInteger,
48
- isIterable,
49
- isObject,
50
- isPrimitive,
51
- isString,
42
+ isArray,
43
+ isFunction,
44
+ isInteger,
45
+ isIterable,
46
+ isObject,
47
+ isPrimitive,
48
+ isString,
52
49
  } from "../../types/is.mjs";
53
- import {Observer} from "../../types/observer.mjs";
54
- import {ProxyObserver} from "../../types/proxyobserver.mjs";
55
- import {validateArray, validateString} from "../../types/validate.mjs";
56
- import {Processing} from "../../util/processing.mjs";
57
- import {STYLE_DISPLAY_MODE_BLOCK} from "./constants.mjs";
58
- import {SelectStyleSheet} from "./stylesheet/select.mjs";
50
+ import { Observer } from "../../types/observer.mjs";
51
+ import { ProxyObserver } from "../../types/proxyobserver.mjs";
52
+ import { validateArray, validateString } from "../../types/validate.mjs";
53
+ import { Processing } from "../../util/processing.mjs";
54
+ import { STYLE_DISPLAY_MODE_BLOCK } from "./constants.mjs";
55
+ import { SelectStyleSheet } from "./stylesheet/select.mjs";
59
56
  import {
60
- getDocumentTranslations,
61
- Translations,
57
+ getDocumentTranslations,
58
+ Translations,
62
59
  } from "../../i18n/translations.mjs";
63
- import {getLocaleOfDocument} from "../../dom/locale.mjs";
64
- import {addErrorAttribute,removeErrorAttribute} from "../../dom/error.mjs";
60
+ import { getLocaleOfDocument } from "../../dom/locale.mjs";
61
+ import { addErrorAttribute, removeErrorAttribute } from "../../dom/error.mjs";
65
62
 
66
63
  export {
67
- Select,
68
- popperElementSymbol,
69
- getSummaryTemplate,
70
- getSelectionTemplate,
64
+ Select,
65
+ popperElementSymbol,
66
+ getSummaryTemplate,
67
+ getSelectionTemplate,
71
68
  };
72
69
 
73
70
  /**
@@ -188,7 +185,7 @@ const popperFilterElementSymbol = Symbol("popperFilterElement");
188
185
  * @type {Symbol}
189
186
  */
190
187
  const popperFilterContainerElementSymbol = Symbol(
191
- "popperFilterContainerElement",
188
+ "popperFilterContainerElement",
192
189
  );
193
190
 
194
191
  /**
@@ -285,484 +282,478 @@ const FILTER_POSITION_INLINE = "inline";
285
282
  * @fires monster-changed
286
283
  */
287
284
  class Select extends CustomControl {
288
- /**
289
- *
290
- */
291
- constructor() {
292
- super();
293
- initOptionObserver.call(this);
294
- }
295
-
296
- /**
297
- * This method is called by the `instanceof` operator.
298
- * @return {Symbol}
299
- */
300
- static get [instanceSymbol]() {
301
- return Symbol.for("@schukai/monster/components/form/select@@instance");
302
- }
303
-
304
- /**
305
- * The current selection of the Select
306
- *
307
- * ```
308
- * e = document.querySelector('monster-select');
309
- * console.log(e.value)
310
- * // ↦ 1
311
- * // ↦ ['1','2']
312
- * ```
313
- *
314
- * @return {string}
315
- */
316
- get value() {
317
- return convertSelectionToValue.call(this, this.getOption("selection"));
318
- }
319
-
320
- /**
321
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals}
322
- * @return {boolean}
323
- */
324
- static get formAssociated() {
325
- return true;
326
- }
327
-
328
- /**
329
- * Set selection
330
- *
331
- * ```
332
- * e = document.querySelector('monster-select');
333
- * e.value=1
334
- * ```
335
- *
336
- * @property {string|array} value
337
- * @throws {Error} unsupported type
338
- * @fires monster-selected this event is fired when the selection is set
339
- */
340
- set value(value) {
341
- const result = convertValueToSelection.call(this, value);
342
- setSelection
343
- .call(this, result.selection)
344
- .then(() => {
345
- })
346
- .catch((e) => {
347
- addErrorAttribute(this, e);
348
- });
349
- }
350
-
351
- /**
352
- * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
353
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
354
- *
355
- * The individual configuration values can be found in the table.
356
- *
357
- * @property {Object} toggleEventType=click,touch List of event types to be observed for opening the dropdown
358
- * @property {boolean} delegatesFocus=false lorem [see mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/delegatesFocus)
359
- * @property {Object[]} options Selection of key identifier pairs available for selection and displayed in the dropdown.
360
- * @property {string} options[].label
361
- * @property {string} options[].value
362
- * @property {string} options[].visibility hidden or visible
363
- * @property {Array} selection Selected options
364
- * @property {Integer} showMaxOptions=10 Maximum number of visible options before a scroll bar should be displayed.
365
- * @property {string} type=radio Multiple (checkbox) or single selection (radio)
366
- * @property {string} name=(random id) Name of the form field
367
- * @property {string} url Load options from server per url
368
- * @property {object} lookup Load options from server per url
369
- * @property {string} lookup.url=null Load options from server per url
370
- * @property {boolean} lookup.grouping=false Load all selected options from server per url at once (true) or one by one (false)
371
- * @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
372
- * @property {String} fetch.redirect=error
373
- * @property {String} fetch.method=GET
374
- * @property {String} fetch.mode=same-origin
375
- * @property {String} fetch.credentials=same-origin
376
- * @property {Object} fetch.headers={"accept":"application/json"}}
377
- * @property {Object} labels
378
- * @property {string} labels.cannot-be-loaded cannot be loaded
379
- * @property {string} labels.no-options-available no options available
380
- * @property {string} labels.select-an-option select an option
381
- * @property {string} labels.no-option no option in the list, maybe you have to change the filter
382
- * @property {Object} features List with features
383
- * @property {Boolean} features.clearAll=true Display of a delete button to delete the entire selection
384
- * @property {Boolean} features.clear=true Display of a delete key for deleting the specific selection
385
- * @property {Boolean} features.lazyLoad=false Load options when first opening the dropdown. (Hint; lazylLoad is not supported with remote filter)
386
- * @property {Boolean} features.closeOnSelect=false Close the dropdown when an option is selected (since 3.54.0)
387
- * @property {Boolean} features.emptyValueIfNoOptions=false If no options are available, the selection is set to an empty array
388
- * @property {Boolean} features.storeFetchedData=false Store fetched data in the object
389
- * @property {Boolean} features.useStrictValueComparison=true Use strict value comparison for the selection
390
- * @property {string} filter.defaultValue=null Default filter value, if the filter is empty, if the default value is null, then no request is made
391
- * @property {Boolean} filter.mode=options Filter mode, values: options, remote, disabled (Hint; lazylLoad is not supported with remote filter, if you use remote filter, the lazyLoad is disabled)
392
- * @property {Object} templates Template definitions
393
- * @property {string} templates.main Main template
394
- * @property {string} templateMapping Mapping of the template placeholders
395
- * @property {string} templateMapping.selected Selected Template
396
- * @property {Object} popper [PopperJS Options](https://popper.js.org/docs/v2/)
397
- * @property {string} popper.placement=bottom PopperJS placement
398
- * @property {Object[]} modifiers={name:offset} PopperJS placement
399
- * @property {Object} mapping
400
- * @property {String} mapping.selector=* Path to select the appropriate entries
401
- * @property {String} mapping.labelTemplate="" template with the label placeholders in the form ${name}, where name is the key (**)
402
- * @property {String} mapping.valueTemplate="" template with the value placeholders in the form ${name}, where name is the key
403
- * @property {Monster.Components.Form~exampleFilterCallback|undefined} mapping.filter Filtering of values via a function
404
- * @property {Object} formatter
405
- * @property {Monster.Components.Form~formatterSelectionCallback|undefined} formatter.selection format selection label
406
- */
407
- get defaults() {
408
- return Object.assign(
409
- {},
410
- super.defaults,
411
- {
412
- toggleEventType: ["click", "touch"],
413
- delegatesFocus: false,
414
- options: [],
415
- selection: [],
416
- showMaxOptions: 10,
417
- type: "radio",
418
- name: new ID("s").toString(),
419
- features: {
420
- clearAll: true,
421
- clear: true,
422
- lazyLoad: false,
423
- closeOnSelect: false,
424
- emptyValueIfNoOptions: false,
425
- storeFetchedData: false,
426
- useStrictValueComparison: false,
427
- },
428
- url: null,
429
- lookup: {
430
- url: null,
431
- grouping: false,
432
- },
433
- labels: getTranslations(),
434
- messages: {
435
- control: null,
436
- selected: null,
437
- emptyOptions: null,
438
- },
439
- fetch: {
440
- redirect: "error",
441
- method: "GET",
442
- mode: "same-origin",
443
- credentials: "same-origin",
444
- headers: {
445
- accept: "application/json",
446
- },
447
- },
448
- filter: {
449
- defaultValue: null,
450
- mode: FILTER_MODE_DISABLED,
451
- position: FILTER_POSITION_INLINE,
452
- marker: {
453
- open: "{",
454
- close: "}",
455
- },
456
- },
457
- classes: {
458
- badge: "monster-badge-primary",
459
- statusOrRemoveBadge: "empty",
460
- },
461
- mapping: {
462
- selector: "*",
463
- labelTemplate: "",
464
- valueTemplate: "",
465
- filter: null,
466
- },
467
- formatter: {
468
- selection: buildSelectionLabel,
469
- },
470
- templates: {
471
- main: getTemplate(),
472
- },
473
- templateMapping: {
474
- /** with the attribute `data-monster-selected-template` the template for the selected options can be defined. */
475
- selected: getSelectionTemplate(),
476
- },
477
-
478
- popper: {
479
- placement: "bottom",
480
- middleware: ["flip", "offset:1"],
481
- },
482
- },
483
- initOptionsFromArguments.call(this),
484
- );
485
- }
486
-
487
- /**
488
- * @return {Select}
489
- */
490
- [assembleMethodSymbol]() {
491
- const self = this;
492
- super[assembleMethodSymbol]();
493
-
494
- initControlReferences.call(self);
495
- initEventHandler.call(self);
496
-
497
- let lazyLoadFlag = self.getOption("features.lazyLoad", false);
498
- let remoteFilterFlag = getFilterMode.call(this) === FILTER_MODE_REMOTE;
499
-
500
- if (getFilterMode.call(this) === FILTER_MODE_REMOTE) {
501
- self.getOption("features.lazyLoad", false);
502
- if (lazyLoadFlag === true) {
503
- addErrorAttribute(
504
- this,
505
- "lazyLoad is not supported with remote filter",
506
- );
507
- lazyLoadFlag = false;
508
- }
509
- }
510
-
511
- if (self.hasAttribute("value")) {
512
- new Processing(10, () => {
513
- this.value = this.getAttribute("value");
514
- })
515
- .run()
516
- .catch((e) => {
517
- addErrorAttribute(this, e);
518
- });
519
- }
520
-
521
- if (self.getOption("url") !== null) {
522
- if (lazyLoadFlag || remoteFilterFlag) {
523
- lookupSelection.call(self);
524
- } else {
525
- self.fetch().catch((e) => {
526
- addErrorAttribute(self, e);
527
- });
528
- }
529
- }
530
-
531
- let lastValue = self.value;
532
- self[internalSymbol].attachObserver(
533
- new Observer(function () {
534
- if (isObject(this) && this instanceof ProxyObserver) {
535
- const n = this.getSubject()?.options?.value;
536
-
537
- if (lastValue !== n) {
538
- lastValue = n;
539
- setSelection
540
- .call(self, n)
541
- .then(() => {
542
- })
543
- .catch((e) => {
544
- addErrorAttribute(self, e);
545
- });
546
- }
547
- }
548
- }),
549
- );
550
-
551
- areOptionsAvailableAndInit.call(self);
552
-
553
- return this;
554
- }
555
-
556
- /**
557
- *
558
- * @return {*}
559
- * @throws {Error} storeFetchedData is not enabled
560
- * @since 3.66.0
561
- */
562
- getLastFetchedData() {
563
- if (this.getOption("features.storeFetchedData") === false) {
564
- throw new Error("storeFetchedData is not enabled");
565
- }
566
-
567
- return this?.[lastFetchedDataSymbol];
568
- }
569
-
570
- /**
571
- * The Button.click() method simulates a click on the internal button element.
572
- *
573
- * @since 3.27.0
574
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click}
575
- */
576
- click() {
577
- if (this.getOption("disabled") === true) {
578
- return;
579
- }
580
-
581
- toggle.call(this);
582
- }
583
-
584
- /**
585
- * The Button.focus() method sets focus on the internal button element.
586
- *
587
- * @since 3.27.0
588
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus}
589
- */
590
- focus(options) {
591
- if (this.getOption("disabled") === true) {
592
- return;
593
- }
594
-
595
- new Processing(() => {
596
- gatherState.call(this);
597
- focusFilter.call(this, options);
598
- })
599
- .run()
600
- .catch((e) => {
601
- addErrorAttribute(this, e);
602
- });
603
- }
604
-
605
- /**
606
- * The Button.blur() method removes focus from the internal button element.
607
- * @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/blur
608
- */
609
- blur() {
610
- new Processing(() => {
611
- gatherState.call(this);
612
- blurFilter.call(this);
613
- })
614
- .run()
615
- .catch((e) => {
616
- addErrorAttribute(this, e);
617
- });
618
- }
619
-
620
- /**
621
- * If no url is specified, the options are taken from the Component itself.
622
- *
623
- * @param {string|URL} url URL to fetch the options
624
- * @return {Promise}
625
- */
626
- fetch(url) {
627
- return fetchIt.call(this, url);
628
- }
629
-
630
- /**
631
- * @return {void}
632
- */
633
- connectedCallback() {
634
- super.connectedCallback();
635
- const document = getDocument();
636
-
637
- for (const [, type] of Object.entries(["click", "touch"])) {
638
- // close on outside ui-events
639
- document.addEventListener(type, this[closeEventHandler]);
640
- }
641
-
642
- parseSlotsToOptions.call(this);
643
- attachResizeObserver.call(this);
644
- updatePopper.call(this);
645
-
646
- new Processing(() => {
647
- gatherState.call(this);
648
- focusFilter.call(this);
649
- })
650
- .run()
651
- .catch((e) => {
652
- addErrorAttribute(this, e);
653
- });
654
- }
655
-
656
- /**
657
- * @return {void}
658
- */
659
- disconnectedCallback() {
660
- super.disconnectedCallback();
661
- const document = getDocument();
662
-
663
- // close on outside ui-events
664
- for (const [, type] of Object.entries(["click", "touch"])) {
665
- document.removeEventListener(type, this[closeEventHandler]);
666
- }
667
-
668
- disconnectResizeObserver.call(this);
669
- }
670
-
671
- /**
672
- * Import Select Options from dataset
673
- * Not to be confused with the control defaults/options
674
- *
675
- * @param {array|object|Map|Set} data
676
- * @return {Select}
677
- * @throws {Error} map is not iterable
678
- * @throws {Error} missing label configuration
679
- * @fires monster-options-set this event is fired when the options are set
680
- */
681
- importOptions(data) {
682
- const mappingOptions = this.getOption("mapping", {});
683
- const selector = mappingOptions?.["selector"];
684
- const labelTemplate = mappingOptions?.["labelTemplate"];
685
- const valueTemplate = mappingOptions?.["valueTemplate"];
686
- const filter = mappingOptions?.["filter"];
687
-
688
- let flag = false;
689
- if (labelTemplate === "") {
690
- addErrorAttribute(this, "empty label template");
691
- flag = true;
692
- }
693
-
694
- if (valueTemplate === "") {
695
- addErrorAttribute(this, "empty value template");
696
- flag = true;
697
- }
698
-
699
- if (flag === true) {
700
- throw new Error("missing label configuration");
701
- }
702
-
703
- const map = buildMap(data, selector, labelTemplate, valueTemplate, filter);
704
-
705
- const options = [];
706
-
707
- if (!isIterable(map)) {
708
- throw new Error("map is not iterable");
709
- }
710
-
711
- const visibility = "visible";
712
-
713
- map.forEach((label, value) => {
714
- options.push({
715
- value,
716
- label,
717
- visibility,
718
- data: map.get(value),
719
- });
720
- });
721
-
722
- runAsOptionLengthChanged.call(this, map.size);
723
- this.setOption("options", options);
724
-
725
- fireCustomEvent(this, "monster-options-set", {
726
- options,
727
- });
728
-
729
- setTimeout(() => {
730
- setSelection.call(this, this.getOption("selection"))
731
- .then(() => {
732
- })
733
- .catch((e) => {
734
- addErrorAttribute(this, e);
735
- });
736
- }, 10)
737
-
738
-
739
- return this;
740
- }
741
-
742
- /**
743
- * @private
744
- * @return {Select}
745
- */
746
- calcAndSetOptionsDimension() {
747
- calcAndSetOptionsDimension.call(this);
748
- return this;
749
- }
750
-
751
- /**
752
- *
753
- * @return {string}
754
- */
755
- static getTag() {
756
- return "monster-select";
757
- }
758
-
759
- /**
760
- *
761
- * @return {CSSStyleSheet[]}
762
- */
763
- static getCSSStyleSheet() {
764
- return [SelectStyleSheet];
765
- }
285
+ /**
286
+ *
287
+ */
288
+ constructor() {
289
+ super();
290
+ initOptionObserver.call(this);
291
+ }
292
+
293
+ /**
294
+ * This method is called by the `instanceof` operator.
295
+ * @return {Symbol}
296
+ */
297
+ static get [instanceSymbol]() {
298
+ return Symbol.for("@schukai/monster/components/form/select@@instance");
299
+ }
300
+
301
+ /**
302
+ * The current selection of the Select
303
+ *
304
+ * ```
305
+ * e = document.querySelector('monster-select');
306
+ * console.log(e.value)
307
+ * // ↦ 1
308
+ * // ↦ ['1','2']
309
+ * ```
310
+ *
311
+ * @return {string}
312
+ */
313
+ get value() {
314
+ return convertSelectionToValue.call(this, this.getOption("selection"));
315
+ }
316
+
317
+ /**
318
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals}
319
+ * @return {boolean}
320
+ */
321
+ static get formAssociated() {
322
+ return true;
323
+ }
324
+
325
+ /**
326
+ * Set selection
327
+ *
328
+ * ```
329
+ * e = document.querySelector('monster-select');
330
+ * e.value=1
331
+ * ```
332
+ *
333
+ * @property {string|array} value
334
+ * @throws {Error} unsupported type
335
+ * @fires monster-selected this event is fired when the selection is set
336
+ */
337
+ set value(value) {
338
+ const result = convertValueToSelection.call(this, value);
339
+ setSelection
340
+ .call(this, result.selection)
341
+ .then(() => {})
342
+ .catch((e) => {
343
+ addErrorAttribute(this, e);
344
+ });
345
+ }
346
+
347
+ /**
348
+ * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
349
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
350
+ *
351
+ * The individual configuration values can be found in the table.
352
+ *
353
+ * @property {Object} toggleEventType=click,touch List of event types to be observed for opening the dropdown
354
+ * @property {boolean} delegatesFocus=false lorem [see mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/delegatesFocus)
355
+ * @property {Object[]} options Selection of key identifier pairs available for selection and displayed in the dropdown.
356
+ * @property {string} options[].label
357
+ * @property {string} options[].value
358
+ * @property {string} options[].visibility hidden or visible
359
+ * @property {Array} selection Selected options
360
+ * @property {Integer} showMaxOptions=10 Maximum number of visible options before a scroll bar should be displayed.
361
+ * @property {string} type=radio Multiple (checkbox) or single selection (radio)
362
+ * @property {string} name=(random id) Name of the form field
363
+ * @property {string} url Load options from server per url
364
+ * @property {object} lookup Load options from server per url
365
+ * @property {string} lookup.url=null Load options from server per url
366
+ * @property {boolean} lookup.grouping=false Load all selected options from server per url at once (true) or one by one (false)
367
+ * @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
368
+ * @property {String} fetch.redirect=error
369
+ * @property {String} fetch.method=GET
370
+ * @property {String} fetch.mode=same-origin
371
+ * @property {String} fetch.credentials=same-origin
372
+ * @property {Object} fetch.headers={"accept":"application/json"}}
373
+ * @property {Object} labels
374
+ * @property {string} labels.cannot-be-loaded cannot be loaded
375
+ * @property {string} labels.no-options-available no options available
376
+ * @property {string} labels.select-an-option select an option
377
+ * @property {string} labels.no-option no option in the list, maybe you have to change the filter
378
+ * @property {Object} features List with features
379
+ * @property {Boolean} features.clearAll=true Display of a delete button to delete the entire selection
380
+ * @property {Boolean} features.clear=true Display of a delete key for deleting the specific selection
381
+ * @property {Boolean} features.lazyLoad=false Load options when first opening the dropdown. (Hint; lazylLoad is not supported with remote filter)
382
+ * @property {Boolean} features.closeOnSelect=false Close the dropdown when an option is selected (since 3.54.0)
383
+ * @property {Boolean} features.emptyValueIfNoOptions=false If no options are available, the selection is set to an empty array
384
+ * @property {Boolean} features.storeFetchedData=false Store fetched data in the object
385
+ * @property {Boolean} features.useStrictValueComparison=true Use strict value comparison for the selection
386
+ * @property {string} filter.defaultValue=null Default filter value, if the filter is empty, if the default value is null, then no request is made
387
+ * @property {Boolean} filter.mode=options Filter mode, values: options, remote, disabled (Hint; lazylLoad is not supported with remote filter, if you use remote filter, the lazyLoad is disabled)
388
+ * @property {Object} templates Template definitions
389
+ * @property {string} templates.main Main template
390
+ * @property {string} templateMapping Mapping of the template placeholders
391
+ * @property {string} templateMapping.selected Selected Template
392
+ * @property {Object} popper [PopperJS Options](https://popper.js.org/docs/v2/)
393
+ * @property {string} popper.placement=bottom PopperJS placement
394
+ * @property {Object[]} modifiers={name:offset} PopperJS placement
395
+ * @property {Object} mapping
396
+ * @property {String} mapping.selector=* Path to select the appropriate entries
397
+ * @property {String} mapping.labelTemplate="" template with the label placeholders in the form ${name}, where name is the key (**)
398
+ * @property {String} mapping.valueTemplate="" template with the value placeholders in the form ${name}, where name is the key
399
+ * @property {Monster.Components.Form~exampleFilterCallback|undefined} mapping.filter Filtering of values via a function
400
+ * @property {Object} formatter
401
+ * @property {Monster.Components.Form~formatterSelectionCallback|undefined} formatter.selection format selection label
402
+ */
403
+ get defaults() {
404
+ return Object.assign(
405
+ {},
406
+ super.defaults,
407
+ {
408
+ toggleEventType: ["click", "touch"],
409
+ delegatesFocus: false,
410
+ options: [],
411
+ selection: [],
412
+ showMaxOptions: 10,
413
+ type: "radio",
414
+ name: new ID("s").toString(),
415
+ features: {
416
+ clearAll: true,
417
+ clear: true,
418
+ lazyLoad: false,
419
+ closeOnSelect: false,
420
+ emptyValueIfNoOptions: false,
421
+ storeFetchedData: false,
422
+ useStrictValueComparison: false,
423
+ },
424
+ url: null,
425
+ lookup: {
426
+ url: null,
427
+ grouping: false,
428
+ },
429
+ labels: getTranslations(),
430
+ messages: {
431
+ control: null,
432
+ selected: null,
433
+ emptyOptions: null,
434
+ },
435
+ fetch: {
436
+ redirect: "error",
437
+ method: "GET",
438
+ mode: "same-origin",
439
+ credentials: "same-origin",
440
+ headers: {
441
+ accept: "application/json",
442
+ },
443
+ },
444
+ filter: {
445
+ defaultValue: null,
446
+ mode: FILTER_MODE_DISABLED,
447
+ position: FILTER_POSITION_INLINE,
448
+ marker: {
449
+ open: "{",
450
+ close: "}",
451
+ },
452
+ },
453
+ classes: {
454
+ badge: "monster-badge-primary",
455
+ statusOrRemoveBadge: "empty",
456
+ },
457
+ mapping: {
458
+ selector: "*",
459
+ labelTemplate: "",
460
+ valueTemplate: "",
461
+ filter: null,
462
+ },
463
+ formatter: {
464
+ selection: buildSelectionLabel,
465
+ },
466
+ templates: {
467
+ main: getTemplate(),
468
+ },
469
+ templateMapping: {
470
+ /** with the attribute `data-monster-selected-template` the template for the selected options can be defined. */
471
+ selected: getSelectionTemplate(),
472
+ },
473
+
474
+ popper: {
475
+ placement: "bottom",
476
+ middleware: ["flip", "offset:1"],
477
+ },
478
+ },
479
+ initOptionsFromArguments.call(this),
480
+ );
481
+ }
482
+
483
+ /**
484
+ * @return {Select}
485
+ */
486
+ [assembleMethodSymbol]() {
487
+ const self = this;
488
+ super[assembleMethodSymbol]();
489
+
490
+ initControlReferences.call(self);
491
+ initEventHandler.call(self);
492
+
493
+ let lazyLoadFlag = self.getOption("features.lazyLoad", false);
494
+ let remoteFilterFlag = getFilterMode.call(this) === FILTER_MODE_REMOTE;
495
+
496
+ if (getFilterMode.call(this) === FILTER_MODE_REMOTE) {
497
+ self.getOption("features.lazyLoad", false);
498
+ if (lazyLoadFlag === true) {
499
+ addErrorAttribute(this, "lazyLoad is not supported with remote filter");
500
+ lazyLoadFlag = false;
501
+ }
502
+ }
503
+
504
+ if (self.hasAttribute("value")) {
505
+ new Processing(10, () => {
506
+ this.value = this.getAttribute("value");
507
+ })
508
+ .run()
509
+ .catch((e) => {
510
+ addErrorAttribute(this, e);
511
+ });
512
+ }
513
+
514
+ if (self.getOption("url") !== null) {
515
+ if (lazyLoadFlag || remoteFilterFlag) {
516
+ lookupSelection.call(self);
517
+ } else {
518
+ self.fetch().catch((e) => {
519
+ addErrorAttribute(self, e);
520
+ });
521
+ }
522
+ }
523
+
524
+ let lastValue = self.value;
525
+ self[internalSymbol].attachObserver(
526
+ new Observer(function () {
527
+ if (isObject(this) && this instanceof ProxyObserver) {
528
+ const n = this.getSubject()?.options?.value;
529
+
530
+ if (lastValue !== n) {
531
+ lastValue = n;
532
+ setSelection
533
+ .call(self, n)
534
+ .then(() => {})
535
+ .catch((e) => {
536
+ addErrorAttribute(self, e);
537
+ });
538
+ }
539
+ }
540
+ }),
541
+ );
542
+
543
+ areOptionsAvailableAndInit.call(self);
544
+
545
+ return this;
546
+ }
547
+
548
+ /**
549
+ *
550
+ * @return {*}
551
+ * @throws {Error} storeFetchedData is not enabled
552
+ * @since 3.66.0
553
+ */
554
+ getLastFetchedData() {
555
+ if (this.getOption("features.storeFetchedData") === false) {
556
+ throw new Error("storeFetchedData is not enabled");
557
+ }
558
+
559
+ return this?.[lastFetchedDataSymbol];
560
+ }
561
+
562
+ /**
563
+ * The Button.click() method simulates a click on the internal button element.
564
+ *
565
+ * @since 3.27.0
566
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click}
567
+ */
568
+ click() {
569
+ if (this.getOption("disabled") === true) {
570
+ return;
571
+ }
572
+
573
+ toggle.call(this);
574
+ }
575
+
576
+ /**
577
+ * The Button.focus() method sets focus on the internal button element.
578
+ *
579
+ * @since 3.27.0
580
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus}
581
+ */
582
+ focus(options) {
583
+ if (this.getOption("disabled") === true) {
584
+ return;
585
+ }
586
+
587
+ new Processing(() => {
588
+ gatherState.call(this);
589
+ focusFilter.call(this, options);
590
+ })
591
+ .run()
592
+ .catch((e) => {
593
+ addErrorAttribute(this, e);
594
+ });
595
+ }
596
+
597
+ /**
598
+ * The Button.blur() method removes focus from the internal button element.
599
+ * @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/blur
600
+ */
601
+ blur() {
602
+ new Processing(() => {
603
+ gatherState.call(this);
604
+ blurFilter.call(this);
605
+ })
606
+ .run()
607
+ .catch((e) => {
608
+ addErrorAttribute(this, e);
609
+ });
610
+ }
611
+
612
+ /**
613
+ * If no url is specified, the options are taken from the Component itself.
614
+ *
615
+ * @param {string|URL} url URL to fetch the options
616
+ * @return {Promise}
617
+ */
618
+ fetch(url) {
619
+ return fetchIt.call(this, url);
620
+ }
621
+
622
+ /**
623
+ * @return {void}
624
+ */
625
+ connectedCallback() {
626
+ super.connectedCallback();
627
+ const document = getDocument();
628
+
629
+ for (const [, type] of Object.entries(["click", "touch"])) {
630
+ // close on outside ui-events
631
+ document.addEventListener(type, this[closeEventHandler]);
632
+ }
633
+
634
+ parseSlotsToOptions.call(this);
635
+ attachResizeObserver.call(this);
636
+ updatePopper.call(this);
637
+
638
+ new Processing(() => {
639
+ gatherState.call(this);
640
+ focusFilter.call(this);
641
+ })
642
+ .run()
643
+ .catch((e) => {
644
+ addErrorAttribute(this, e);
645
+ });
646
+ }
647
+
648
+ /**
649
+ * @return {void}
650
+ */
651
+ disconnectedCallback() {
652
+ super.disconnectedCallback();
653
+ const document = getDocument();
654
+
655
+ // close on outside ui-events
656
+ for (const [, type] of Object.entries(["click", "touch"])) {
657
+ document.removeEventListener(type, this[closeEventHandler]);
658
+ }
659
+
660
+ disconnectResizeObserver.call(this);
661
+ }
662
+
663
+ /**
664
+ * Import Select Options from dataset
665
+ * Not to be confused with the control defaults/options
666
+ *
667
+ * @param {array|object|Map|Set} data
668
+ * @return {Select}
669
+ * @throws {Error} map is not iterable
670
+ * @throws {Error} missing label configuration
671
+ * @fires monster-options-set this event is fired when the options are set
672
+ */
673
+ importOptions(data) {
674
+ const mappingOptions = this.getOption("mapping", {});
675
+ const selector = mappingOptions?.["selector"];
676
+ const labelTemplate = mappingOptions?.["labelTemplate"];
677
+ const valueTemplate = mappingOptions?.["valueTemplate"];
678
+ const filter = mappingOptions?.["filter"];
679
+
680
+ let flag = false;
681
+ if (labelTemplate === "") {
682
+ addErrorAttribute(this, "empty label template");
683
+ flag = true;
684
+ }
685
+
686
+ if (valueTemplate === "") {
687
+ addErrorAttribute(this, "empty value template");
688
+ flag = true;
689
+ }
690
+
691
+ if (flag === true) {
692
+ throw new Error("missing label configuration");
693
+ }
694
+
695
+ const map = buildMap(data, selector, labelTemplate, valueTemplate, filter);
696
+
697
+ const options = [];
698
+
699
+ if (!isIterable(map)) {
700
+ throw new Error("map is not iterable");
701
+ }
702
+
703
+ const visibility = "visible";
704
+
705
+ map.forEach((label, value) => {
706
+ options.push({
707
+ value,
708
+ label,
709
+ visibility,
710
+ data: map.get(value),
711
+ });
712
+ });
713
+
714
+ runAsOptionLengthChanged.call(this, map.size);
715
+ this.setOption("options", options);
716
+
717
+ fireCustomEvent(this, "monster-options-set", {
718
+ options,
719
+ });
720
+
721
+ setTimeout(() => {
722
+ setSelection
723
+ .call(this, this.getOption("selection"))
724
+ .then(() => {})
725
+ .catch((e) => {
726
+ addErrorAttribute(this, e);
727
+ });
728
+ }, 10);
729
+
730
+ return this;
731
+ }
732
+
733
+ /**
734
+ * @private
735
+ * @return {Select}
736
+ */
737
+ calcAndSetOptionsDimension() {
738
+ calcAndSetOptionsDimension.call(this);
739
+ return this;
740
+ }
741
+
742
+ /**
743
+ *
744
+ * @return {string}
745
+ */
746
+ static getTag() {
747
+ return "monster-select";
748
+ }
749
+
750
+ /**
751
+ *
752
+ * @return {CSSStyleSheet[]}
753
+ */
754
+ static getCSSStyleSheet() {
755
+ return [SelectStyleSheet];
756
+ }
766
757
  }
767
758
 
768
759
  /**
@@ -770,285 +761,285 @@ class Select extends CustomControl {
770
761
  * @returns {object}
771
762
  */
772
763
  function getTranslations() {
773
- const locale = getLocaleOfDocument();
774
- switch (locale.language) {
775
- case "de":
776
- return {
777
- "cannot-be-loaded": "Kann nicht geladen werden",
778
- "no-options-available": "Keine Optionen verfügbar.",
779
- "click-to-load-options": "Klicken, um Optionen zu laden.",
780
- "select-an-option": "Wähle eine Option",
781
- "summary-text": {
782
- zero: "Keine Einträge ausgewählt",
783
- one: '<span class="monster-badge-primary-pill">1</span> Eintrag ausgewählt',
784
- other:
785
- '<span class="monster-badge-primary-pill">${count}</span> Einträge ausgewählt',
786
- },
787
- "no-options": "Leider gibt es keine Optionen in der Liste.",
788
- "no-options-found":
789
- "Keine Optionen in der Liste verfügbar. Bitte ändern Sie den Filter.",
790
- };
791
- case "fr":
792
- return {
793
- "cannot-be-loaded": "Impossible de charger",
794
- "no-options-available": "Aucune option disponible.",
795
- "click-to-load-options": "Cliquez pour charger les options.",
796
- "select-an-option": "Sélectionnez une option",
797
- "summary-text": {
798
- zero: "Aucune entrée sélectionnée",
799
- one: '<span class="monster-badge-primary-pill">1</span> entrée sélectionnée',
800
- other:
801
- '<span class="monster-badge-primary-pill">${count}</span> entrées sélectionnées',
802
- },
803
- "no-options":
804
- "Malheureusement, il n'y a pas d'options disponibles dans la liste.",
805
- "no-options-found":
806
- "Aucune option disponible dans la liste. Veuillez modifier le filtre.",
807
- };
808
-
809
- case "sp":
810
- return {
811
- "cannot-be-loaded": "No se puede cargar",
812
- "no-options-available": "No hay opciones disponibles.",
813
- "click-to-load-options": "Haga clic para cargar opciones.",
814
- "select-an-option": "Seleccione una opción",
815
- "summary-text": {
816
- zero: "No se seleccionaron entradas",
817
- one: '<span class="monster-badge-primary-pill">1</span> entrada seleccionada',
818
- other:
819
- '<span class="monster-badge-primary-pill">${count}</span> entradas seleccionadas',
820
- },
821
- "no-options":
822
- "Desafortunadamente, no hay opciones disponibles en la lista.",
823
- "no-options-found":
824
- "No hay opciones disponibles en la lista. Considere modificar el filtro.",
825
- };
826
- case "it":
827
- return {
828
- "cannot-be-loaded": "Non può essere caricato",
829
- "no-options-available": "Nessuna opzione disponibile.",
830
- "click-to-load-options": "Clicca per caricare le opzioni.",
831
- "select-an-option": "Seleziona un'opzione",
832
- "summary-text": {
833
- zero: "Nessuna voce selezionata",
834
- one: '<span class="monster-badge-primary-pill">1</span> voce selezionata',
835
- other:
836
- '<span class="monster-badge-primary-pill">${count}</span> voci selezionate',
837
- },
838
- "no-options": "Purtroppo, non ci sono opzioni disponibili nella lista.",
839
- "no-options-found":
840
- "Nessuna opzione disponibile nella lista. Si prega di modificare il filtro.",
841
- };
842
- case "pl":
843
- return {
844
- "cannot-be-loaded": "Nie można załadować",
845
- "no-options-available": "Brak dostępnych opcji.",
846
- "click-to-load-options": "Kliknij, aby załadować opcje.",
847
- "select-an-option": "Wybierz opcję",
848
- "summary-text": {
849
- zero: "Nie wybrano żadnych wpisów",
850
- one: '<span class="monster-badge-primary-pill">1</span> wpis został wybrany',
851
- other:
852
- '<span class="monster-badge-primary-pill">${count}</span> wpisy zostały wybrane',
853
- },
854
- "no-options": "Niestety, nie ma dostępnych opcji na liście.",
855
- "no-options-found":
856
- "Brak dostępnych opcji na liście. Rozważ zmianę filtra.",
857
- };
858
- case "no":
859
- return {
860
- "cannot-be-loaded": "Kan ikke lastes",
861
- "no-options-available": "Ingen alternativer tilgjengelig.",
862
- "click-to-load-options": "Klikk for å laste alternativer.",
863
- "select-an-option": "Velg et alternativ",
864
- "summary-text": {
865
- zero: "Ingen oppføringer ble valgt",
866
- one: '<span class="monster-badge-primary-pill">1</span> oppføring valgt',
867
- other:
868
- '<span class="monster-badge-primary-pill">${count}</span> oppføringer valgt',
869
- },
870
- "no-options":
871
- "Dessverre er det ingen alternativer tilgjengelig i listen.",
872
- "no-options-found":
873
- "Ingen alternativer tilgjengelig på listen. Vurder å endre filteret.",
874
- };
875
-
876
- case "dk":
877
- return {
878
- "cannot-be-loaded": "Kan ikke indlæses",
879
- "no-options-available": "Ingen muligheder tilgængelige.",
880
- "click-to-load-options": "Klik for at indlæse muligheder.",
881
- "select-an-option": "Vælg en mulighed",
882
- "summary-text": {
883
- zero: "Ingen indlæg blev valgt",
884
- one: '<span class="monster-badge-primary-pill">1</span> indlæg blev valgt',
885
- other:
886
- '<span class="monster-badge-primary-pill">${count}</span> indlæg blev valgt',
887
- },
888
- "no-options":
889
- "Desværre er der ingen muligheder tilgængelige på listen.",
890
- "no-options-found":
891
- "Ingen muligheder tilgængelige på listen. Overvej at ændre filteret.",
892
- };
893
- case "sw":
894
- return {
895
- "cannot-be-loaded": "Kan inte laddas",
896
- "no-options-available": "Inga alternativ tillgängliga.",
897
- "click-to-load-options": "Klicka för att ladda alternativ.",
898
- "select-an-option": "Välj ett alternativ",
899
- "summary-text": {
900
- zero: "Inga poster valdes",
901
- one: '<span class="monster-badge-primary-pill">1</span> post valdes',
902
- other:
903
- '<span class="monster-badge-primary-pill">${count}</span> poster valdes',
904
- },
905
- "no-options": "Tyvärr finns det inga alternativ tillgängliga i listan.",
906
- "no-options-found":
907
- "Inga alternativ finns tillgängliga i listan. Överväg att modifiera filtret.",
908
- };
909
-
910
- default:
911
- case "en":
912
- return {
913
- "cannot-be-loaded": "Cannot be loaded",
914
- "no-options-available": "No options available.",
915
- "click-to-load-options": "Click to load options.",
916
- "select-an-option": "Select an option",
917
- "summary-text": {
918
- zero: "No entries were selected",
919
- one: '<span class="monster-badge-primary-pill">1</span> entry was selected',
920
- other:
921
- '<span class="monster-badge-primary-pill">${count}</span> entries were selected',
922
- },
923
- "no-options":
924
- "Unfortunately, there are no options available in the list.",
925
- "no-options-found":
926
- "No options are available in the list. Please consider modifying the filter.",
927
- };
928
- }
764
+ const locale = getLocaleOfDocument();
765
+ switch (locale.language) {
766
+ case "de":
767
+ return {
768
+ "cannot-be-loaded": "Kann nicht geladen werden",
769
+ "no-options-available": "Keine Optionen verfügbar.",
770
+ "click-to-load-options": "Klicken, um Optionen zu laden.",
771
+ "select-an-option": "Wähle eine Option",
772
+ "summary-text": {
773
+ zero: "Keine Einträge ausgewählt",
774
+ one: '<span class="monster-badge-primary-pill">1</span> Eintrag ausgewählt',
775
+ other:
776
+ '<span class="monster-badge-primary-pill">${count}</span> Einträge ausgewählt',
777
+ },
778
+ "no-options": "Leider gibt es keine Optionen in der Liste.",
779
+ "no-options-found":
780
+ "Keine Optionen in der Liste verfügbar. Bitte ändern Sie den Filter.",
781
+ };
782
+ case "fr":
783
+ return {
784
+ "cannot-be-loaded": "Impossible de charger",
785
+ "no-options-available": "Aucune option disponible.",
786
+ "click-to-load-options": "Cliquez pour charger les options.",
787
+ "select-an-option": "Sélectionnez une option",
788
+ "summary-text": {
789
+ zero: "Aucune entrée sélectionnée",
790
+ one: '<span class="monster-badge-primary-pill">1</span> entrée sélectionnée',
791
+ other:
792
+ '<span class="monster-badge-primary-pill">${count}</span> entrées sélectionnées',
793
+ },
794
+ "no-options":
795
+ "Malheureusement, il n'y a pas d'options disponibles dans la liste.",
796
+ "no-options-found":
797
+ "Aucune option disponible dans la liste. Veuillez modifier le filtre.",
798
+ };
799
+
800
+ case "sp":
801
+ return {
802
+ "cannot-be-loaded": "No se puede cargar",
803
+ "no-options-available": "No hay opciones disponibles.",
804
+ "click-to-load-options": "Haga clic para cargar opciones.",
805
+ "select-an-option": "Seleccione una opción",
806
+ "summary-text": {
807
+ zero: "No se seleccionaron entradas",
808
+ one: '<span class="monster-badge-primary-pill">1</span> entrada seleccionada',
809
+ other:
810
+ '<span class="monster-badge-primary-pill">${count}</span> entradas seleccionadas',
811
+ },
812
+ "no-options":
813
+ "Desafortunadamente, no hay opciones disponibles en la lista.",
814
+ "no-options-found":
815
+ "No hay opciones disponibles en la lista. Considere modificar el filtro.",
816
+ };
817
+ case "it":
818
+ return {
819
+ "cannot-be-loaded": "Non può essere caricato",
820
+ "no-options-available": "Nessuna opzione disponibile.",
821
+ "click-to-load-options": "Clicca per caricare le opzioni.",
822
+ "select-an-option": "Seleziona un'opzione",
823
+ "summary-text": {
824
+ zero: "Nessuna voce selezionata",
825
+ one: '<span class="monster-badge-primary-pill">1</span> voce selezionata',
826
+ other:
827
+ '<span class="monster-badge-primary-pill">${count}</span> voci selezionate',
828
+ },
829
+ "no-options": "Purtroppo, non ci sono opzioni disponibili nella lista.",
830
+ "no-options-found":
831
+ "Nessuna opzione disponibile nella lista. Si prega di modificare il filtro.",
832
+ };
833
+ case "pl":
834
+ return {
835
+ "cannot-be-loaded": "Nie można załadować",
836
+ "no-options-available": "Brak dostępnych opcji.",
837
+ "click-to-load-options": "Kliknij, aby załadować opcje.",
838
+ "select-an-option": "Wybierz opcję",
839
+ "summary-text": {
840
+ zero: "Nie wybrano żadnych wpisów",
841
+ one: '<span class="monster-badge-primary-pill">1</span> wpis został wybrany',
842
+ other:
843
+ '<span class="monster-badge-primary-pill">${count}</span> wpisy zostały wybrane',
844
+ },
845
+ "no-options": "Niestety, nie ma dostępnych opcji na liście.",
846
+ "no-options-found":
847
+ "Brak dostępnych opcji na liście. Rozważ zmianę filtra.",
848
+ };
849
+ case "no":
850
+ return {
851
+ "cannot-be-loaded": "Kan ikke lastes",
852
+ "no-options-available": "Ingen alternativer tilgjengelig.",
853
+ "click-to-load-options": "Klikk for å laste alternativer.",
854
+ "select-an-option": "Velg et alternativ",
855
+ "summary-text": {
856
+ zero: "Ingen oppføringer ble valgt",
857
+ one: '<span class="monster-badge-primary-pill">1</span> oppføring valgt',
858
+ other:
859
+ '<span class="monster-badge-primary-pill">${count}</span> oppføringer valgt',
860
+ },
861
+ "no-options":
862
+ "Dessverre er det ingen alternativer tilgjengelig i listen.",
863
+ "no-options-found":
864
+ "Ingen alternativer tilgjengelig på listen. Vurder å endre filteret.",
865
+ };
866
+
867
+ case "dk":
868
+ return {
869
+ "cannot-be-loaded": "Kan ikke indlæses",
870
+ "no-options-available": "Ingen muligheder tilgængelige.",
871
+ "click-to-load-options": "Klik for at indlæse muligheder.",
872
+ "select-an-option": "Vælg en mulighed",
873
+ "summary-text": {
874
+ zero: "Ingen indlæg blev valgt",
875
+ one: '<span class="monster-badge-primary-pill">1</span> indlæg blev valgt',
876
+ other:
877
+ '<span class="monster-badge-primary-pill">${count}</span> indlæg blev valgt',
878
+ },
879
+ "no-options":
880
+ "Desværre er der ingen muligheder tilgængelige på listen.",
881
+ "no-options-found":
882
+ "Ingen muligheder tilgængelige på listen. Overvej at ændre filteret.",
883
+ };
884
+ case "sw":
885
+ return {
886
+ "cannot-be-loaded": "Kan inte laddas",
887
+ "no-options-available": "Inga alternativ tillgängliga.",
888
+ "click-to-load-options": "Klicka för att ladda alternativ.",
889
+ "select-an-option": "Välj ett alternativ",
890
+ "summary-text": {
891
+ zero: "Inga poster valdes",
892
+ one: '<span class="monster-badge-primary-pill">1</span> post valdes',
893
+ other:
894
+ '<span class="monster-badge-primary-pill">${count}</span> poster valdes',
895
+ },
896
+ "no-options": "Tyvärr finns det inga alternativ tillgängliga i listan.",
897
+ "no-options-found":
898
+ "Inga alternativ finns tillgängliga i listan. Överväg att modifiera filtret.",
899
+ };
900
+
901
+ default:
902
+ case "en":
903
+ return {
904
+ "cannot-be-loaded": "Cannot be loaded",
905
+ "no-options-available": "No options available.",
906
+ "click-to-load-options": "Click to load options.",
907
+ "select-an-option": "Select an option",
908
+ "summary-text": {
909
+ zero: "No entries were selected",
910
+ one: '<span class="monster-badge-primary-pill">1</span> entry was selected',
911
+ other:
912
+ '<span class="monster-badge-primary-pill">${count}</span> entries were selected',
913
+ },
914
+ "no-options":
915
+ "Unfortunately, there are no options available in the list.",
916
+ "no-options-found":
917
+ "No options are available in the list. Please consider modifying the filter.",
918
+ };
919
+ }
929
920
  }
930
921
 
931
922
  /**
932
923
  * @private
933
924
  */
934
925
  function lookupSelection() {
935
- const self = this;
936
-
937
- setTimeout(() => {
938
- const selection = self.getOption("selection");
939
- if (selection.length === 0) {
940
- return;
941
- }
942
-
943
- if (self[isLoadingSymbol] === true) {
944
- return;
945
- }
946
-
947
- if (self[lazyLoadDoneSymbol] === true) {
948
- return;
949
- }
950
-
951
- let url = self.getOption("url");
952
- let lookupUrl = self.getOption("lookup.url");
953
- if (lookupUrl !== null) {
954
- url = lookupUrl;
955
- }
956
-
957
- if (this.getOption("lookup.grouping") === true) {
958
- filterFromRemoteByValue
959
- .call(
960
- self,
961
- url,
962
- selection.map((s) => s?.["value"]),
963
- )
964
- .catch((e) => {
965
- addErrorAttribute(self, e);
966
- });
967
- return;
968
- }
969
-
970
- for (const s of selection) {
971
- if (s?.["value"]) {
972
- filterFromRemoteByValue.call(self, url, s?.["value"]).catch((e) => {
973
- addErrorAttribute(self, e);
974
- });
975
- }
976
- }
977
- }, 100);
926
+ const self = this;
927
+
928
+ setTimeout(() => {
929
+ const selection = self.getOption("selection");
930
+ if (selection.length === 0) {
931
+ return;
932
+ }
933
+
934
+ if (self[isLoadingSymbol] === true) {
935
+ return;
936
+ }
937
+
938
+ if (self[lazyLoadDoneSymbol] === true) {
939
+ return;
940
+ }
941
+
942
+ let url = self.getOption("url");
943
+ let lookupUrl = self.getOption("lookup.url");
944
+ if (lookupUrl !== null) {
945
+ url = lookupUrl;
946
+ }
947
+
948
+ if (this.getOption("lookup.grouping") === true) {
949
+ filterFromRemoteByValue
950
+ .call(
951
+ self,
952
+ url,
953
+ selection.map((s) => s?.["value"]),
954
+ )
955
+ .catch((e) => {
956
+ addErrorAttribute(self, e);
957
+ });
958
+ return;
959
+ }
960
+
961
+ for (const s of selection) {
962
+ if (s?.["value"]) {
963
+ filterFromRemoteByValue.call(self, url, s?.["value"]).catch((e) => {
964
+ addErrorAttribute(self, e);
965
+ });
966
+ }
967
+ }
968
+ }, 100);
978
969
  }
979
970
 
980
971
  function fetchIt(url, controlOptions) {
981
- if (url instanceof URL) {
982
- url = url.toString();
983
- }
984
-
985
- if (url !== undefined && url !== null) {
986
- url = validateString(url);
987
- } else {
988
- url = this.getOption("url");
989
- if (url === null) {
990
- return Promise.reject(new Error("No url defined"));
991
- }
992
- }
993
-
994
- return new Promise((resolve, reject) => {
995
- setStatusOrRemoveBadges.call(this, "loading");
996
-
997
- new Processing(10, () => {
998
- fetchData
999
- .call(this, url)
1000
- .then((map) => {
1001
- if (
1002
- isObject(map) ||
1003
- isArray(map) ||
1004
- map instanceof Set ||
1005
- map instanceof Map
1006
- ) {
1007
- try {
1008
- this.importOptions(map);
1009
- } catch (e) {
1010
- setStatusOrRemoveBadges.call(this, "error");
1011
- reject(e);
1012
- return;
1013
- }
1014
-
1015
- this[lastFetchedDataSymbol] = map;
1016
-
1017
- let result;
1018
- const selection = this.getOption("selection");
1019
- let newValue = [];
1020
- if (selection) {
1021
- newValue = selection;
1022
- } else if (this.hasAttribute("value")) {
1023
- newValue = this.getAttribute("value");
1024
- }
1025
-
1026
- result = setSelection.call(this, newValue);
1027
- requestAnimationFrame(() => {
1028
- checkOptionState.call(this);
1029
- setStatusOrRemoveBadges.call(this, "closed");
1030
- updatePopper.call(this);
1031
- resolve(result);
1032
- });
1033
-
1034
- return;
1035
- }
1036
-
1037
- setStatusOrRemoveBadges.call(this, "error");
1038
- reject(new Error("invalid response"));
1039
- })
1040
- .catch((e) => {
1041
- setStatusOrRemoveBadges.call(this, "error");
1042
- reject(e);
1043
- });
1044
- })
1045
- .run()
1046
- .catch((e) => {
1047
- setStatusOrRemoveBadges.call(this, "error");
1048
- addErrorAttribute(this, e);
1049
- reject(e);
1050
- });
1051
- });
972
+ if (url instanceof URL) {
973
+ url = url.toString();
974
+ }
975
+
976
+ if (url !== undefined && url !== null) {
977
+ url = validateString(url);
978
+ } else {
979
+ url = this.getOption("url");
980
+ if (url === null) {
981
+ return Promise.reject(new Error("No url defined"));
982
+ }
983
+ }
984
+
985
+ return new Promise((resolve, reject) => {
986
+ setStatusOrRemoveBadges.call(this, "loading");
987
+
988
+ new Processing(10, () => {
989
+ fetchData
990
+ .call(this, url)
991
+ .then((map) => {
992
+ if (
993
+ isObject(map) ||
994
+ isArray(map) ||
995
+ map instanceof Set ||
996
+ map instanceof Map
997
+ ) {
998
+ try {
999
+ this.importOptions(map);
1000
+ } catch (e) {
1001
+ setStatusOrRemoveBadges.call(this, "error");
1002
+ reject(e);
1003
+ return;
1004
+ }
1005
+
1006
+ this[lastFetchedDataSymbol] = map;
1007
+
1008
+ let result;
1009
+ const selection = this.getOption("selection");
1010
+ let newValue = [];
1011
+ if (selection) {
1012
+ newValue = selection;
1013
+ } else if (this.hasAttribute("value")) {
1014
+ newValue = this.getAttribute("value");
1015
+ }
1016
+
1017
+ result = setSelection.call(this, newValue);
1018
+ requestAnimationFrame(() => {
1019
+ checkOptionState.call(this);
1020
+ setStatusOrRemoveBadges.call(this, "closed");
1021
+ updatePopper.call(this);
1022
+ resolve(result);
1023
+ });
1024
+
1025
+ return;
1026
+ }
1027
+
1028
+ setStatusOrRemoveBadges.call(this, "error");
1029
+ reject(new Error("invalid response"));
1030
+ })
1031
+ .catch((e) => {
1032
+ setStatusOrRemoveBadges.call(this, "error");
1033
+ reject(e);
1034
+ });
1035
+ })
1036
+ .run()
1037
+ .catch((e) => {
1038
+ setStatusOrRemoveBadges.call(this, "error");
1039
+ addErrorAttribute(this, e);
1040
+ reject(e);
1041
+ });
1042
+ });
1052
1043
  }
1053
1044
 
1054
1045
  /**
@@ -1063,62 +1054,59 @@ function fetchIt(url, controlOptions) {
1063
1054
  * @return {object}
1064
1055
  */
1065
1056
  function initOptionsFromArguments() {
1066
- const options = {};
1067
-
1068
- const template = this.getAttribute("data-monster-selected-template");
1069
- if (isString(template)) {
1070
- if (!options["templateMapping"]) options["templateMapping"] = {};
1071
-
1072
- switch (template) {
1073
- case "summary":
1074
- case "default":
1075
- options["templateMapping"]["selected"] = getSummaryTemplate();
1076
- break;
1077
- case "selected":
1078
- options["templateMapping"]["selected"] = getSelectionTemplate();
1079
- break;
1080
- default:
1081
- addErrorAttribute(
1082
- this,
1083
- "invalid template, use summary or selected",
1084
- );
1085
- }
1086
- }
1087
-
1088
- return options;
1057
+ const options = {};
1058
+
1059
+ const template = this.getAttribute("data-monster-selected-template");
1060
+ if (isString(template)) {
1061
+ if (!options["templateMapping"]) options["templateMapping"] = {};
1062
+
1063
+ switch (template) {
1064
+ case "summary":
1065
+ case "default":
1066
+ options["templateMapping"]["selected"] = getSummaryTemplate();
1067
+ break;
1068
+ case "selected":
1069
+ options["templateMapping"]["selected"] = getSelectionTemplate();
1070
+ break;
1071
+ default:
1072
+ addErrorAttribute(this, "invalid template, use summary or selected");
1073
+ }
1074
+ }
1075
+
1076
+ return options;
1089
1077
  }
1090
1078
 
1091
1079
  /**
1092
1080
  * @private
1093
1081
  */
1094
1082
  function attachResizeObserver() {
1095
- // against flickering
1096
- this[resizeObserverSymbol] = new ResizeObserver((entries) => {
1097
- if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
1098
- try {
1099
- this[timerCallbackSymbol].touch();
1100
- return;
1101
- } catch (e) {
1102
- delete this[timerCallbackSymbol];
1103
- }
1104
- }
1105
-
1106
- this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
1107
- updatePopper.call(this);
1108
- delete this[timerCallbackSymbol];
1109
- });
1110
- });
1111
-
1112
- this[resizeObserverSymbol].observe(this.parentElement);
1083
+ // against flickering
1084
+ this[resizeObserverSymbol] = new ResizeObserver((entries) => {
1085
+ if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
1086
+ try {
1087
+ this[timerCallbackSymbol].touch();
1088
+ return;
1089
+ } catch (e) {
1090
+ delete this[timerCallbackSymbol];
1091
+ }
1092
+ }
1093
+
1094
+ this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
1095
+ updatePopper.call(this);
1096
+ delete this[timerCallbackSymbol];
1097
+ });
1098
+ });
1099
+
1100
+ this[resizeObserverSymbol].observe(this.parentElement);
1113
1101
  }
1114
1102
 
1115
1103
  /**
1116
1104
  * @private
1117
1105
  */
1118
1106
  function disconnectResizeObserver() {
1119
- if (this[resizeObserverSymbol] instanceof ResizeObserver) {
1120
- this[resizeObserverSymbol].disconnect();
1121
- }
1107
+ if (this[resizeObserverSymbol] instanceof ResizeObserver) {
1108
+ this[resizeObserverSymbol].disconnect();
1109
+ }
1122
1110
  }
1123
1111
 
1124
1112
  /**
@@ -1126,7 +1114,7 @@ function disconnectResizeObserver() {
1126
1114
  * @returns {string}
1127
1115
  */
1128
1116
  function getSelectionTemplate() {
1129
- return `<div data-monster-role="selection" part="selection"
1117
+ return `<div data-monster-role="selection" part="selection"
1130
1118
  data-monster-insert="selection path:selection" role="search"
1131
1119
  ><input type="text" role="searchbox"
1132
1120
  part="inline-filter" name="inline-filter"
@@ -1142,7 +1130,7 @@ function getSelectionTemplate() {
1142
1130
  * @returns {string}
1143
1131
  */
1144
1132
  function getSummaryTemplate() {
1145
- return `<div data-monster-role="selection" role="search" part="summary">
1133
+ return `<div data-monster-role="selection" role="search" part="summary">
1146
1134
  <input type="text" role="searchbox"
1147
1135
  part="inline-filter" name="inline-filter"
1148
1136
  data-monster-role="filter"
@@ -1158,35 +1146,35 @@ function getSummaryTemplate() {
1158
1146
  * @private
1159
1147
  */
1160
1148
  function parseSlotsToOptions() {
1161
- let options = this.getOption("options");
1162
- if (!isIterable(options)) {
1163
- options = [];
1164
- }
1165
-
1166
- let counter = 1;
1167
- getSlottedElements.call(this, "div").forEach((node) => {
1168
- let value = (counter++).toString();
1169
- let visibility = "visible";
1170
-
1171
- if (node.hasAttribute("data-monster-value")) {
1172
- value = node.getAttribute("data-monster-value");
1173
- }
1174
-
1175
- let label = node.outerHTML;
1176
-
1177
- if (node.style.display === "none") {
1178
- visibility = "hidden";
1179
- }
1180
-
1181
- options.push({
1182
- value,
1183
- label,
1184
- visibility,
1185
- });
1186
- });
1187
-
1188
- runAsOptionLengthChanged.call(this, options.length);
1189
- this.setOption("options", options);
1149
+ let options = this.getOption("options");
1150
+ if (!isIterable(options)) {
1151
+ options = [];
1152
+ }
1153
+
1154
+ let counter = 1;
1155
+ getSlottedElements.call(this, "div").forEach((node) => {
1156
+ let value = (counter++).toString();
1157
+ let visibility = "visible";
1158
+
1159
+ if (node.hasAttribute("data-monster-value")) {
1160
+ value = node.getAttribute("data-monster-value");
1161
+ }
1162
+
1163
+ let label = node.outerHTML;
1164
+
1165
+ if (node.style.display === "none") {
1166
+ visibility = "hidden";
1167
+ }
1168
+
1169
+ options.push({
1170
+ value,
1171
+ label,
1172
+ visibility,
1173
+ });
1174
+ });
1175
+
1176
+ runAsOptionLengthChanged.call(this, options.length);
1177
+ this.setOption("options", options);
1190
1178
  }
1191
1179
 
1192
1180
  /**
@@ -1196,39 +1184,39 @@ function parseSlotsToOptions() {
1196
1184
  * @param {int} targetLength
1197
1185
  */
1198
1186
  function runAsOptionLengthChanged(targetLength) {
1199
- const self = this;
1200
-
1201
- if (!self[optionsElementSymbol]) {
1202
- return;
1203
- }
1204
-
1205
- const callback = function (mutationsList, observer) {
1206
- const run = false;
1207
- for (const mutation of mutationsList) {
1208
- if (mutation.type === "childList") {
1209
- const run = true;
1210
- break;
1211
- }
1212
- }
1213
-
1214
- if (run === true) {
1215
- const nodes = self[optionsElementSymbol].querySelectorAll(
1216
- `div[${ATTRIBUTE_ROLE}=option]`,
1217
- );
1218
-
1219
- if (nodes.length === targetLength) {
1220
- checkOptionState.call(self);
1221
- observer.disconnect();
1222
- }
1223
- }
1224
- };
1225
-
1226
- const observer = new MutationObserver(callback);
1227
- observer.observe(self[optionsElementSymbol], {
1228
- attributes: false,
1229
- childList: true,
1230
- subtree: true,
1231
- });
1187
+ const self = this;
1188
+
1189
+ if (!self[optionsElementSymbol]) {
1190
+ return;
1191
+ }
1192
+
1193
+ const callback = function (mutationsList, observer) {
1194
+ const run = false;
1195
+ for (const mutation of mutationsList) {
1196
+ if (mutation.type === "childList") {
1197
+ const run = true;
1198
+ break;
1199
+ }
1200
+ }
1201
+
1202
+ if (run === true) {
1203
+ const nodes = self[optionsElementSymbol].querySelectorAll(
1204
+ `div[${ATTRIBUTE_ROLE}=option]`,
1205
+ );
1206
+
1207
+ if (nodes.length === targetLength) {
1208
+ checkOptionState.call(self);
1209
+ observer.disconnect();
1210
+ }
1211
+ }
1212
+ };
1213
+
1214
+ const observer = new MutationObserver(callback);
1215
+ observer.observe(self[optionsElementSymbol], {
1216
+ attributes: false,
1217
+ childList: true,
1218
+ subtree: true,
1219
+ });
1232
1220
  }
1233
1221
 
1234
1222
  /**
@@ -1237,38 +1225,38 @@ function runAsOptionLengthChanged(targetLength) {
1237
1225
  * @return {*}
1238
1226
  */
1239
1227
  function buildSelectionLabel(value) {
1240
- const options = this.getOption("options");
1241
-
1242
- for (let i = 0; i < options.length; i++) {
1243
- let o = options?.[i];
1244
- let l, v, v2;
1245
-
1246
- if (this.getOption("features.useStrictValueComparison") === true) {
1247
- v = value;
1248
- } else {
1249
- v = `${value}`;
1250
- }
1251
-
1252
- if (isPrimitive(o) && o === value) {
1253
- return o;
1254
- } else if (!isObject(o)) {
1255
- continue;
1256
- }
1257
-
1258
- if (this.getOption("features.useStrictValueComparison") === true) {
1259
- l = o?.["label"];
1260
- v2 = o?.["value"];
1261
- } else {
1262
- l = `${o?.["label"]}`;
1263
- v2 = `${o?.["value"]}`;
1264
- }
1265
-
1266
- if (v2 === v) {
1267
- return l;
1268
- }
1269
- }
1270
-
1271
- return undefined;
1228
+ const options = this.getOption("options");
1229
+
1230
+ for (let i = 0; i < options.length; i++) {
1231
+ let o = options?.[i];
1232
+ let l, v, v2;
1233
+
1234
+ if (this.getOption("features.useStrictValueComparison") === true) {
1235
+ v = value;
1236
+ } else {
1237
+ v = `${value}`;
1238
+ }
1239
+
1240
+ if (isPrimitive(o) && o === value) {
1241
+ return o;
1242
+ } else if (!isObject(o)) {
1243
+ continue;
1244
+ }
1245
+
1246
+ if (this.getOption("features.useStrictValueComparison") === true) {
1247
+ l = o?.["label"];
1248
+ v2 = o?.["value"];
1249
+ } else {
1250
+ l = `${o?.["label"]}`;
1251
+ v2 = `${o?.["value"]}`;
1252
+ }
1253
+
1254
+ if (v2 === v) {
1255
+ return l;
1256
+ }
1257
+ }
1258
+
1259
+ return undefined;
1272
1260
  }
1273
1261
 
1274
1262
  /**
@@ -1278,17 +1266,17 @@ function buildSelectionLabel(value) {
1278
1266
  * @throws {Error} no value found
1279
1267
  */
1280
1268
  function getSelectionLabel(value) {
1281
- const callback = this.getOption("formatter.selection");
1282
- if (isFunction(callback)) {
1283
- const label = callback.call(this, value);
1284
- if (isString(label)) return label;
1285
- }
1269
+ const callback = this.getOption("formatter.selection");
1270
+ if (isFunction(callback)) {
1271
+ const label = callback.call(this, value);
1272
+ if (isString(label)) return label;
1273
+ }
1286
1274
 
1287
- if (isString(value) || isInteger(value)) {
1288
- return `${value}`;
1289
- }
1275
+ if (isString(value) || isInteger(value)) {
1276
+ return `${value}`;
1277
+ }
1290
1278
 
1291
- return this.getOption("labels.cannot-be-loaded", value);
1279
+ return this.getOption("labels.cannot-be-loaded", value);
1292
1280
  }
1293
1281
 
1294
1282
  /**
@@ -1296,25 +1284,25 @@ function getSelectionLabel(value) {
1296
1284
  * @param {Event} event
1297
1285
  */
1298
1286
  function handleToggleKeyboardEvents(event) {
1299
- switch (event?.["code"]) {
1300
- case "Escape":
1301
- toggle.call(this);
1302
- event.preventDefault();
1303
- break;
1304
- case "Space":
1305
- toggle.call(this);
1306
- event.preventDefault();
1307
- break;
1308
- case "ArrowDown":
1309
- show.call(this);
1310
- activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1311
- event.preventDefault();
1312
- break;
1313
- case "ArrowUp":
1314
- hide.call(this);
1315
- event.preventDefault();
1316
- break;
1317
- }
1287
+ switch (event?.["code"]) {
1288
+ case "Escape":
1289
+ toggle.call(this);
1290
+ event.preventDefault();
1291
+ break;
1292
+ case "Space":
1293
+ toggle.call(this);
1294
+ event.preventDefault();
1295
+ break;
1296
+ case "ArrowDown":
1297
+ show.call(this);
1298
+ activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1299
+ event.preventDefault();
1300
+ break;
1301
+ case "ArrowUp":
1302
+ hide.call(this);
1303
+ event.preventDefault();
1304
+ break;
1305
+ }
1318
1306
  }
1319
1307
 
1320
1308
  /**
@@ -1324,32 +1312,32 @@ function handleToggleKeyboardEvents(event) {
1324
1312
  * @this CustomElement
1325
1313
  */
1326
1314
  function initOptionObserver() {
1327
- const self = this;
1328
-
1329
- self.attachObserver(
1330
- new Observer(function () {
1331
- new Processing(() => {
1332
- try {
1333
- self.updateI18n();
1334
- } catch (e) {
1335
- addErrorAttribute(self, e);
1336
- requestAnimationFrame(() => {
1337
- setStatusOrRemoveBadges.call(self, "error");
1338
- });
1339
- }
1340
- try {
1341
- areOptionsAvailableAndInit.call(self);
1342
- } catch (e) {
1343
- addErrorAttribute(self, e);
1344
- requestAnimationFrame(() => {
1345
- setStatusOrRemoveBadges.call(self, "error");
1346
- });
1347
- }
1348
-
1349
- setSummaryAndControlText.call(self);
1350
- }).run();
1351
- }),
1352
- );
1315
+ const self = this;
1316
+
1317
+ self.attachObserver(
1318
+ new Observer(function () {
1319
+ new Processing(() => {
1320
+ try {
1321
+ self.updateI18n();
1322
+ } catch (e) {
1323
+ addErrorAttribute(self, e);
1324
+ requestAnimationFrame(() => {
1325
+ setStatusOrRemoveBadges.call(self, "error");
1326
+ });
1327
+ }
1328
+ try {
1329
+ areOptionsAvailableAndInit.call(self);
1330
+ } catch (e) {
1331
+ addErrorAttribute(self, e);
1332
+ requestAnimationFrame(() => {
1333
+ setStatusOrRemoveBadges.call(self, "error");
1334
+ });
1335
+ }
1336
+
1337
+ setSummaryAndControlText.call(self);
1338
+ }).run();
1339
+ }),
1340
+ );
1353
1341
  }
1354
1342
 
1355
1343
  /**
@@ -1357,17 +1345,16 @@ function initOptionObserver() {
1357
1345
  * @returns {Translations}
1358
1346
  */
1359
1347
  function getDefaultTranslation() {
1360
- const translation = new Translations("en").assignTranslations(
1361
- this.getOption("labels", {}),
1362
- );
1348
+ const translation = new Translations("en").assignTranslations(
1349
+ this.getOption("labels", {}),
1350
+ );
1363
1351
 
1364
- try {
1365
- const doc = getDocumentTranslations();
1366
- translation.locale = doc.locale;
1367
- } catch (e) {
1368
- }
1352
+ try {
1353
+ const doc = getDocumentTranslations();
1354
+ translation.locale = doc.locale;
1355
+ } catch (e) {}
1369
1356
 
1370
- return translation;
1357
+ return translation;
1371
1358
  }
1372
1359
 
1373
1360
  /**
@@ -1375,36 +1362,36 @@ function getDefaultTranslation() {
1375
1362
  * @return {string|*}
1376
1363
  */
1377
1364
  function setSummaryAndControlText() {
1378
- const translations = getDefaultTranslation.call(this);
1379
- const selections = this.getOption("selection");
1380
-
1381
- const text = translations.getPluralRuleText(
1382
- "summary-text",
1383
- selections.length,
1384
- "",
1385
- );
1386
-
1387
- const selectedText = new Formatter({
1388
- count: String(selections.length),
1389
- }).format(text);
1390
-
1391
- this.setOption("messages.selected", selectedText);
1392
-
1393
- const current = this.getOption("messages.control");
1394
- const msg = this.getOption("labels.select-an-option");
1395
-
1396
- if (
1397
- current === "" ||
1398
- current === undefined ||
1399
- current === msg ||
1400
- current === null
1401
- ) {
1402
- if (selections.length === 0) {
1403
- this.setOption("messages.control", msg);
1404
- } else {
1405
- this.setOption("messages.control", "");
1406
- }
1407
- }
1365
+ const translations = getDefaultTranslation.call(this);
1366
+ const selections = this.getOption("selection");
1367
+
1368
+ const text = translations.getPluralRuleText(
1369
+ "summary-text",
1370
+ selections.length,
1371
+ "",
1372
+ );
1373
+
1374
+ const selectedText = new Formatter({
1375
+ count: String(selections.length),
1376
+ }).format(text);
1377
+
1378
+ this.setOption("messages.selected", selectedText);
1379
+
1380
+ const current = this.getOption("messages.control");
1381
+ const msg = this.getOption("labels.select-an-option");
1382
+
1383
+ if (
1384
+ current === "" ||
1385
+ current === undefined ||
1386
+ current === msg ||
1387
+ current === null
1388
+ ) {
1389
+ if (selections.length === 0) {
1390
+ this.setOption("messages.control", msg);
1391
+ } else {
1392
+ this.setOption("messages.control", "");
1393
+ }
1394
+ }
1408
1395
  }
1409
1396
 
1410
1397
  /**
@@ -1412,9 +1399,9 @@ function setSummaryAndControlText() {
1412
1399
  * @return {NodeList}
1413
1400
  */
1414
1401
  function getOptionElements() {
1415
- return this[optionsElementSymbol].querySelectorAll(
1416
- `[${ATTRIBUTE_ROLE}=option]`,
1417
- );
1402
+ return this[optionsElementSymbol].querySelectorAll(
1403
+ `[${ATTRIBUTE_ROLE}=option]`,
1404
+ );
1418
1405
  }
1419
1406
 
1420
1407
  /**
@@ -1438,75 +1425,75 @@ function getOptionElements() {
1438
1425
  * @private
1439
1426
  */
1440
1427
  function calcAndSetOptionsDimension() {
1441
- const options = getOptionElements.call(this);
1442
- const container = this[optionsElementSymbol];
1443
- if (!(container instanceof HTMLElement && options instanceof NodeList)) {
1444
- return;
1445
- }
1446
-
1447
- let visible = 0;
1448
- let optionHeight = 0;
1449
- const max = this.getOption("showMaxOptions", 10);
1450
-
1451
- let scrollFlag = false;
1452
- for (const [, option] of Object.entries(options)) {
1453
- const computedStyle = getGlobal().getComputedStyle(option);
1454
- if (computedStyle.display === "none") continue;
1455
-
1456
- let h = option.getBoundingClientRect().height;
1457
- h += parseInt(computedStyle.getPropertyValue("margin-top"), 10);
1458
- h += parseInt(computedStyle.getPropertyValue("margin-bottom"), 10);
1459
- optionHeight += h;
1460
-
1461
- visible++;
1462
-
1463
- if (visible > max) {
1464
- break;
1465
- }
1466
- }
1467
-
1468
- if (visible > max) {
1469
- visible = max;
1470
- scrollFlag = true;
1471
- }
1472
-
1473
- if (visible === 0) {
1474
- if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
1475
- this.setOption(
1476
- "messages.emptyOptions",
1477
- this.getOption("labels.no-options-available"),
1478
- );
1479
- } else {
1480
- this.setOption(
1481
- "messages.emptyOptions",
1482
- this.getOption("labels.no-options-found"),
1483
- );
1484
- }
1485
- this[noOptionsAvailableElementSymbol].classList.remove("d-none");
1486
- } else {
1487
- this[noOptionsAvailableElementSymbol].classList.add("d-none");
1488
- }
1489
-
1490
- const styles = getGlobal().getComputedStyle(this[optionsElementSymbol]);
1491
- let padding = parseInt(styles.getPropertyValue("padding-top"), 10);
1492
- padding += parseInt(styles.getPropertyValue("padding-bottom"), 10);
1493
-
1494
- let margin = parseInt(styles.getPropertyValue("margin-top"), 10);
1495
- margin += parseInt(styles.getPropertyValue("margin-bottom"), 10);
1496
-
1497
- const containerHeight = optionHeight + padding + margin;
1498
- container.style.height = `${containerHeight}px`;
1499
-
1500
- if (scrollFlag === true) {
1501
- container.style.overflowY = "scroll";
1502
- } else {
1503
- container.style.overflowY = "auto";
1504
- }
1505
-
1506
- const domRect = this[controlElementSymbol].getBoundingClientRect();
1507
-
1508
- this[popperElementSymbol].style.width = `${domRect.width}px`;
1509
- container.style.overflowX = "auto";
1428
+ const options = getOptionElements.call(this);
1429
+ const container = this[optionsElementSymbol];
1430
+ if (!(container instanceof HTMLElement && options instanceof NodeList)) {
1431
+ return;
1432
+ }
1433
+
1434
+ let visible = 0;
1435
+ let optionHeight = 0;
1436
+ const max = this.getOption("showMaxOptions", 10);
1437
+
1438
+ let scrollFlag = false;
1439
+ for (const [, option] of Object.entries(options)) {
1440
+ const computedStyle = getGlobal().getComputedStyle(option);
1441
+ if (computedStyle.display === "none") continue;
1442
+
1443
+ let h = option.getBoundingClientRect().height;
1444
+ h += parseInt(computedStyle.getPropertyValue("margin-top"), 10);
1445
+ h += parseInt(computedStyle.getPropertyValue("margin-bottom"), 10);
1446
+ optionHeight += h;
1447
+
1448
+ visible++;
1449
+
1450
+ if (visible > max) {
1451
+ break;
1452
+ }
1453
+ }
1454
+
1455
+ if (visible > max) {
1456
+ visible = max;
1457
+ scrollFlag = true;
1458
+ }
1459
+
1460
+ if (visible === 0) {
1461
+ if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
1462
+ this.setOption(
1463
+ "messages.emptyOptions",
1464
+ this.getOption("labels.no-options-available"),
1465
+ );
1466
+ } else {
1467
+ this.setOption(
1468
+ "messages.emptyOptions",
1469
+ this.getOption("labels.no-options-found"),
1470
+ );
1471
+ }
1472
+ this[noOptionsAvailableElementSymbol].classList.remove("d-none");
1473
+ } else {
1474
+ this[noOptionsAvailableElementSymbol].classList.add("d-none");
1475
+ }
1476
+
1477
+ const styles = getGlobal().getComputedStyle(this[optionsElementSymbol]);
1478
+ let padding = parseInt(styles.getPropertyValue("padding-top"), 10);
1479
+ padding += parseInt(styles.getPropertyValue("padding-bottom"), 10);
1480
+
1481
+ let margin = parseInt(styles.getPropertyValue("margin-top"), 10);
1482
+ margin += parseInt(styles.getPropertyValue("margin-bottom"), 10);
1483
+
1484
+ const containerHeight = optionHeight + padding + margin;
1485
+ container.style.height = `${containerHeight}px`;
1486
+
1487
+ if (scrollFlag === true) {
1488
+ container.style.overflowY = "scroll";
1489
+ } else {
1490
+ container.style.overflowY = "auto";
1491
+ }
1492
+
1493
+ const domRect = this[controlElementSymbol].getBoundingClientRect();
1494
+
1495
+ this[popperElementSymbol].style.width = `${domRect.width}px`;
1496
+ container.style.overflowX = "auto";
1510
1497
  }
1511
1498
 
1512
1499
  /**
@@ -1515,126 +1502,126 @@ function calcAndSetOptionsDimension() {
1515
1502
  * @throws {Error} no shadow-root is defined
1516
1503
  */
1517
1504
  function activateCurrentOption(direction) {
1518
- if (!this.shadowRoot) {
1519
- throw new Error("no shadow-root is defined");
1520
- }
1521
-
1522
- let focused = this.shadowRoot.querySelector(`[${ATTRIBUTE_PREFIX}focused]`);
1523
-
1524
- if (
1525
- !(focused instanceof HTMLElement) ||
1526
- focused.matches("[data-monster-visibility=hidden]")
1527
- ) {
1528
- for (const [, e] of Object.entries(
1529
- this.shadowRoot.querySelectorAll(`[${ATTRIBUTE_ROLE}=option]`),
1530
- )) {
1531
- if (e.matches("[data-monster-visibility=visible]")) {
1532
- focused = e;
1533
- break;
1534
- }
1535
- }
1536
- } else {
1537
- if (direction === FOCUS_DIRECTION_DOWN) {
1538
- while (focused.nextSibling) {
1539
- focused = focused.nextSibling;
1540
-
1541
- if (
1542
- focused instanceof HTMLElement &&
1543
- focused.hasAttribute(ATTRIBUTE_ROLE) &&
1544
- focused.getAttribute(ATTRIBUTE_ROLE) === "option" &&
1545
- focused.matches("[data-monster-visibility=visible]") &&
1546
- focused.matches(":not([data-monster-filtered=true])")
1547
- ) {
1548
- break;
1549
- }
1550
- }
1551
- } else {
1552
- let found = false;
1553
- while (focused.previousSibling) {
1554
- focused = focused.previousSibling;
1555
- if (
1556
- focused instanceof HTMLElement &&
1557
- focused.hasAttribute(ATTRIBUTE_ROLE) &&
1558
- focused.getAttribute(ATTRIBUTE_ROLE) === "option" &&
1559
- focused.matches("[data-monster-visibility=visible]") &&
1560
- focused.matches(":not([data-monster-filtered=true])")
1561
- ) {
1562
- found = true;
1563
- break;
1564
- }
1565
- }
1566
- if (found === false) {
1567
- focusFilter.call(this);
1568
- }
1569
- }
1570
- }
1571
-
1572
- new Processing(() => {
1573
- if (focused instanceof HTMLElement) {
1574
- this.shadowRoot
1575
- .querySelectorAll(`[${ATTRIBUTE_PREFIX}focused]`)
1576
- .forEach((e) => {
1577
- e.removeAttribute(`${ATTRIBUTE_PREFIX}focused`);
1578
- });
1579
-
1580
- focused.focus();
1581
- focused.setAttribute(`${ATTRIBUTE_PREFIX}focused`, true);
1582
- }
1583
- })
1584
- .run()
1585
- .catch((e) => {
1586
- addErrorAttribute(this, e);
1587
- });
1505
+ if (!this.shadowRoot) {
1506
+ throw new Error("no shadow-root is defined");
1507
+ }
1508
+
1509
+ let focused = this.shadowRoot.querySelector(`[${ATTRIBUTE_PREFIX}focused]`);
1510
+
1511
+ if (
1512
+ !(focused instanceof HTMLElement) ||
1513
+ focused.matches("[data-monster-visibility=hidden]")
1514
+ ) {
1515
+ for (const [, e] of Object.entries(
1516
+ this.shadowRoot.querySelectorAll(`[${ATTRIBUTE_ROLE}=option]`),
1517
+ )) {
1518
+ if (e.matches("[data-monster-visibility=visible]")) {
1519
+ focused = e;
1520
+ break;
1521
+ }
1522
+ }
1523
+ } else {
1524
+ if (direction === FOCUS_DIRECTION_DOWN) {
1525
+ while (focused.nextSibling) {
1526
+ focused = focused.nextSibling;
1527
+
1528
+ if (
1529
+ focused instanceof HTMLElement &&
1530
+ focused.hasAttribute(ATTRIBUTE_ROLE) &&
1531
+ focused.getAttribute(ATTRIBUTE_ROLE) === "option" &&
1532
+ focused.matches("[data-monster-visibility=visible]") &&
1533
+ focused.matches(":not([data-monster-filtered=true])")
1534
+ ) {
1535
+ break;
1536
+ }
1537
+ }
1538
+ } else {
1539
+ let found = false;
1540
+ while (focused.previousSibling) {
1541
+ focused = focused.previousSibling;
1542
+ if (
1543
+ focused instanceof HTMLElement &&
1544
+ focused.hasAttribute(ATTRIBUTE_ROLE) &&
1545
+ focused.getAttribute(ATTRIBUTE_ROLE) === "option" &&
1546
+ focused.matches("[data-monster-visibility=visible]") &&
1547
+ focused.matches(":not([data-monster-filtered=true])")
1548
+ ) {
1549
+ found = true;
1550
+ break;
1551
+ }
1552
+ }
1553
+ if (found === false) {
1554
+ focusFilter.call(this);
1555
+ }
1556
+ }
1557
+ }
1558
+
1559
+ new Processing(() => {
1560
+ if (focused instanceof HTMLElement) {
1561
+ this.shadowRoot
1562
+ .querySelectorAll(`[${ATTRIBUTE_PREFIX}focused]`)
1563
+ .forEach((e) => {
1564
+ e.removeAttribute(`${ATTRIBUTE_PREFIX}focused`);
1565
+ });
1566
+
1567
+ focused.focus();
1568
+ focused.setAttribute(`${ATTRIBUTE_PREFIX}focused`, true);
1569
+ }
1570
+ })
1571
+ .run()
1572
+ .catch((e) => {
1573
+ addErrorAttribute(this, e);
1574
+ });
1588
1575
  }
1589
1576
 
1590
1577
  /**
1591
1578
  * @private
1592
1579
  */
1593
1580
  function filterOptions() {
1594
- new Processing(() => {
1595
- let filterValue;
1596
-
1597
- switch (this.getOption("filter.position")) {
1598
- case FILTER_POSITION_INLINE:
1599
- if (this[inlineFilterElementSymbol] instanceof HTMLElement) {
1600
- filterValue = this[inlineFilterElementSymbol].value.toLowerCase();
1601
- } else {
1602
- return;
1603
- }
1604
-
1605
- break;
1606
- case FILTER_POSITION_POPPER:
1607
- default:
1608
- if (this[popperFilterElementSymbol] instanceof HTMLInputElement) {
1609
- filterValue = this[popperFilterElementSymbol].value.toLowerCase();
1610
- } else {
1611
- return;
1612
- }
1613
- }
1614
-
1615
- const options = this.getOption("options");
1616
- for (const [i, option] of Object.entries(options)) {
1617
- if (option.label.toLowerCase().indexOf(filterValue) === -1) {
1618
- this.setOption(`options.${i}.filtered`, "true");
1619
- } else {
1620
- this.setOption(`options.${i}.filtered`, undefined);
1621
- }
1622
- }
1623
- })
1624
- .run()
1625
- .then(() => {
1626
- new Processing(100, () => {
1627
- calcAndSetOptionsDimension.call(this);
1628
- focusFilter.call(this);
1629
- })
1630
- .run()
1631
- .catch((e) => {
1632
- addErrorAttribute(this, e);
1633
- });
1634
- })
1635
- .catch((e) => {
1636
- addErrorAttribute(this, e);
1637
- });
1581
+ new Processing(() => {
1582
+ let filterValue;
1583
+
1584
+ switch (this.getOption("filter.position")) {
1585
+ case FILTER_POSITION_INLINE:
1586
+ if (this[inlineFilterElementSymbol] instanceof HTMLElement) {
1587
+ filterValue = this[inlineFilterElementSymbol].value.toLowerCase();
1588
+ } else {
1589
+ return;
1590
+ }
1591
+
1592
+ break;
1593
+ case FILTER_POSITION_POPPER:
1594
+ default:
1595
+ if (this[popperFilterElementSymbol] instanceof HTMLInputElement) {
1596
+ filterValue = this[popperFilterElementSymbol].value.toLowerCase();
1597
+ } else {
1598
+ return;
1599
+ }
1600
+ }
1601
+
1602
+ const options = this.getOption("options");
1603
+ for (const [i, option] of Object.entries(options)) {
1604
+ if (option.label.toLowerCase().indexOf(filterValue) === -1) {
1605
+ this.setOption(`options.${i}.filtered`, "true");
1606
+ } else {
1607
+ this.setOption(`options.${i}.filtered`, undefined);
1608
+ }
1609
+ }
1610
+ })
1611
+ .run()
1612
+ .then(() => {
1613
+ new Processing(100, () => {
1614
+ calcAndSetOptionsDimension.call(this);
1615
+ focusFilter.call(this);
1616
+ })
1617
+ .run()
1618
+ .catch((e) => {
1619
+ addErrorAttribute(this, e);
1620
+ });
1621
+ })
1622
+ .catch((e) => {
1623
+ addErrorAttribute(this, e);
1624
+ });
1638
1625
  }
1639
1626
 
1640
1627
  /**
@@ -1642,37 +1629,37 @@ function filterOptions() {
1642
1629
  * @param {Event} event
1643
1630
  */
1644
1631
  function handleFilterKeyboardEvents(event) {
1645
- const shiftKey = event?.["shiftKey"];
1646
-
1647
- switch (event?.["code"]) {
1648
- case "Tab":
1649
- activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1650
- event.preventDefault();
1651
- break;
1652
- case "Escape":
1653
- toggle.call(this);
1654
- event.preventDefault();
1655
- break;
1656
- case "Tab" && shiftKey === true:
1657
- case "ArrowUp":
1658
- activateCurrentOption.call(this, FOCUS_DIRECTION_UP);
1659
- event.preventDefault();
1660
- break;
1661
- case "Tab" && !shiftKey:
1662
- case "ArrowDown":
1663
- activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1664
- event.preventDefault();
1665
- break;
1666
- default:
1667
- if (
1668
- this.getOption("features.lazyLoad") === true &&
1669
- this[lazyLoadDoneSymbol] !== true
1670
- ) {
1671
- this.click();
1672
- }
1673
-
1674
- handleFilterKeyEvents.call(this);
1675
- }
1632
+ const shiftKey = event?.["shiftKey"];
1633
+
1634
+ switch (event?.["code"]) {
1635
+ case "Tab":
1636
+ activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1637
+ event.preventDefault();
1638
+ break;
1639
+ case "Escape":
1640
+ toggle.call(this);
1641
+ event.preventDefault();
1642
+ break;
1643
+ case "Tab" && shiftKey === true:
1644
+ case "ArrowUp":
1645
+ activateCurrentOption.call(this, FOCUS_DIRECTION_UP);
1646
+ event.preventDefault();
1647
+ break;
1648
+ case "Tab" && !shiftKey:
1649
+ case "ArrowDown":
1650
+ activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1651
+ event.preventDefault();
1652
+ break;
1653
+ default:
1654
+ if (
1655
+ this.getOption("features.lazyLoad") === true &&
1656
+ this[lazyLoadDoneSymbol] !== true
1657
+ ) {
1658
+ this.click();
1659
+ }
1660
+
1661
+ handleFilterKeyEvents.call(this);
1662
+ }
1676
1663
  }
1677
1664
 
1678
1665
  /**
@@ -1686,89 +1673,86 @@ function handleFilterKeyboardEvents(event) {
1686
1673
  * @return {void} This method does not return anything.
1687
1674
  */
1688
1675
  function handleFilterKeyEvents() {
1689
- if (this[keyFilterEventSymbol] instanceof DeadMansSwitch) {
1690
- try {
1691
- this[keyFilterEventSymbol].touch();
1692
- return;
1693
- } catch (e) {
1694
- delete this[keyFilterEventSymbol];
1695
- }
1696
- }
1697
-
1698
- this[keyFilterEventSymbol] = new DeadMansSwitch(200, () => {
1699
- if (getFilterMode.call(this) !== FILTER_MODE_REMOTE) {
1700
- filterOptions.call(this);
1701
- } else {
1702
- filterFromRemote.call(this).catch((e) => {
1703
- addErrorAttribute(this, e);
1704
- });
1705
- }
1706
-
1707
- delete this[keyFilterEventSymbol];
1708
- });
1676
+ if (this[keyFilterEventSymbol] instanceof DeadMansSwitch) {
1677
+ try {
1678
+ this[keyFilterEventSymbol].touch();
1679
+ return;
1680
+ } catch (e) {
1681
+ delete this[keyFilterEventSymbol];
1682
+ }
1683
+ }
1684
+
1685
+ this[keyFilterEventSymbol] = new DeadMansSwitch(200, () => {
1686
+ if (getFilterMode.call(this) !== FILTER_MODE_REMOTE) {
1687
+ filterOptions.call(this);
1688
+ } else {
1689
+ filterFromRemote.call(this).catch((e) => {
1690
+ addErrorAttribute(this, e);
1691
+ });
1692
+ }
1693
+
1694
+ delete this[keyFilterEventSymbol];
1695
+ });
1709
1696
  }
1710
1697
 
1711
1698
  /**
1712
1699
  * @private
1713
1700
  */
1714
1701
  function filterFromRemote() {
1715
- if (
1716
- !(this[inlineFilterElementSymbol] instanceof HTMLElement) &&
1717
- !(this[popperFilterElementSymbol] instanceof HTMLElement)
1718
- ) {
1719
- return;
1720
- }
1721
-
1722
- show.call(this);
1723
-
1724
- const url = this.getOption("url");
1725
- if (!url) {
1726
- addErrorAttribute(
1727
- this,
1728
- "Missing URL for Remote Filter.",
1729
- );
1730
- return;
1731
- }
1732
-
1733
- let filterValue;
1734
-
1735
- switch (this.getOption("filter.position")) {
1736
- case FILTER_POSITION_INLINE:
1737
- if (this[inlineFilterElementSymbol] instanceof HTMLElement) {
1738
- filterValue = this[inlineFilterElementSymbol].value.toLowerCase();
1739
- }
1740
-
1741
- break;
1742
- case FILTER_POSITION_POPPER:
1743
- default:
1744
- if (this[popperFilterElementSymbol] instanceof HTMLInputElement) {
1745
- filterValue = this[popperFilterElementSymbol].value.toLowerCase();
1746
- }
1747
- }
1748
-
1749
- return filterFromRemoteByValue.call(this, url, filterValue);
1702
+ if (
1703
+ !(this[inlineFilterElementSymbol] instanceof HTMLElement) &&
1704
+ !(this[popperFilterElementSymbol] instanceof HTMLElement)
1705
+ ) {
1706
+ return;
1707
+ }
1708
+
1709
+ show.call(this);
1710
+
1711
+ const url = this.getOption("url");
1712
+ if (!url) {
1713
+ addErrorAttribute(this, "Missing URL for Remote Filter.");
1714
+ return;
1715
+ }
1716
+
1717
+ let filterValue;
1718
+
1719
+ switch (this.getOption("filter.position")) {
1720
+ case FILTER_POSITION_INLINE:
1721
+ if (this[inlineFilterElementSymbol] instanceof HTMLElement) {
1722
+ filterValue = this[inlineFilterElementSymbol].value.toLowerCase();
1723
+ }
1724
+
1725
+ break;
1726
+ case FILTER_POSITION_POPPER:
1727
+ default:
1728
+ if (this[popperFilterElementSymbol] instanceof HTMLInputElement) {
1729
+ filterValue = this[popperFilterElementSymbol].value.toLowerCase();
1730
+ }
1731
+ }
1732
+
1733
+ return filterFromRemoteByValue.call(this, url, filterValue);
1750
1734
  }
1751
1735
 
1752
1736
  function formatURL(url, value) {
1753
- if (value === undefined || value === null || value === "") {
1754
- value = this.getOption("filter.defaultValue");
1755
- if (value === undefined || value === null || value === "") {
1756
- value = disabledRequestMarker.toString();
1757
- }
1758
- }
1759
-
1760
- const formatter = new Formatter({filter: encodeURI(value)});
1761
- const openMarker = this.getOption("filter.marker.open");
1762
- let closeMarker = this.getOption("filter.marker.close");
1763
- if (!closeMarker) {
1764
- closeMarker = openMarker;
1765
- }
1766
-
1767
- if (openMarker && closeMarker) {
1768
- formatter.setMarker(openMarker, closeMarker);
1769
- }
1770
-
1771
- return formatter.format(url);
1737
+ if (value === undefined || value === null || value === "") {
1738
+ value = this.getOption("filter.defaultValue");
1739
+ if (value === undefined || value === null || value === "") {
1740
+ value = disabledRequestMarker.toString();
1741
+ }
1742
+ }
1743
+
1744
+ const formatter = new Formatter({ filter: encodeURI(value) });
1745
+ const openMarker = this.getOption("filter.marker.open");
1746
+ let closeMarker = this.getOption("filter.marker.close");
1747
+ if (!closeMarker) {
1748
+ closeMarker = openMarker;
1749
+ }
1750
+
1751
+ if (openMarker && closeMarker) {
1752
+ formatter.setMarker(openMarker, closeMarker);
1753
+ }
1754
+
1755
+ return formatter.format(url);
1772
1756
  }
1773
1757
 
1774
1758
  /**
@@ -1778,28 +1762,28 @@ function formatURL(url, value) {
1778
1762
  * @returns {Promise<unknown>}
1779
1763
  */
1780
1764
  function filterFromRemoteByValue(optionUrl, value) {
1781
- return new Processing(() => {
1782
- let url = formatURL.call(this, optionUrl, value);
1783
- if (url.indexOf(disabledRequestMarker.toString()) !== -1) {
1784
- return;
1785
- }
1786
-
1787
- fetchIt
1788
- .call(this, url, {
1789
- disableHiding: true,
1790
- })
1791
- .then(() => {
1792
- checkOptionState.call(this);
1793
- show.call(this);
1794
- })
1795
- .catch((e) => {
1796
- throw e;
1797
- });
1798
- })
1799
- .run()
1800
- .catch((e) => {
1801
- throw e;
1802
- });
1765
+ return new Processing(() => {
1766
+ let url = formatURL.call(this, optionUrl, value);
1767
+ if (url.indexOf(disabledRequestMarker.toString()) !== -1) {
1768
+ return;
1769
+ }
1770
+
1771
+ fetchIt
1772
+ .call(this, url, {
1773
+ disableHiding: true,
1774
+ })
1775
+ .then(() => {
1776
+ checkOptionState.call(this);
1777
+ show.call(this);
1778
+ })
1779
+ .catch((e) => {
1780
+ throw e;
1781
+ });
1782
+ })
1783
+ .run()
1784
+ .catch((e) => {
1785
+ throw e;
1786
+ });
1803
1787
  }
1804
1788
 
1805
1789
  /**
@@ -1807,50 +1791,50 @@ function filterFromRemoteByValue(optionUrl, value) {
1807
1791
  * @private
1808
1792
  */
1809
1793
  function handleOptionKeyboardEvents(event) {
1810
- const shiftKey = event?.["shiftKey"];
1811
-
1812
- switch (event?.["code"]) {
1813
- case "Escape":
1814
- toggle.call(this);
1815
- event.preventDefault();
1816
- break;
1817
- case "Enter":
1818
- case "Space":
1819
- const path = event.composedPath();
1820
- const element = path?.[0];
1821
- if (element instanceof HTMLElement) {
1822
- const input = element.getElementsByTagName("input");
1823
- if (!input) {
1824
- return;
1825
- }
1826
- fireEvent(input, "click");
1827
- }
1828
- event.preventDefault();
1829
- break;
1830
-
1831
- case "Tab" && shiftKey === true:
1832
- case "ArrowUp":
1833
- activateCurrentOption.call(this, FOCUS_DIRECTION_UP);
1834
- event.preventDefault();
1835
- break;
1836
-
1837
- case "Tab" && !shiftKey:
1838
- case "ArrowLeft":
1839
- case "ArrowRight":
1840
- // handled by tree select
1841
- break;
1842
- case "ArrowDown":
1843
- activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1844
- event.preventDefault();
1845
- break;
1846
- default:
1847
- const p = event.composedPath();
1848
- if (p?.[0] instanceof HTMLInputElement) {
1849
- return;
1850
- }
1851
- focusFilter.call(this);
1852
- break;
1853
- }
1794
+ const shiftKey = event?.["shiftKey"];
1795
+
1796
+ switch (event?.["code"]) {
1797
+ case "Escape":
1798
+ toggle.call(this);
1799
+ event.preventDefault();
1800
+ break;
1801
+ case "Enter":
1802
+ case "Space":
1803
+ const path = event.composedPath();
1804
+ const element = path?.[0];
1805
+ if (element instanceof HTMLElement) {
1806
+ const input = element.getElementsByTagName("input");
1807
+ if (!input) {
1808
+ return;
1809
+ }
1810
+ fireEvent(input, "click");
1811
+ }
1812
+ event.preventDefault();
1813
+ break;
1814
+
1815
+ case "Tab" && shiftKey === true:
1816
+ case "ArrowUp":
1817
+ activateCurrentOption.call(this, FOCUS_DIRECTION_UP);
1818
+ event.preventDefault();
1819
+ break;
1820
+
1821
+ case "Tab" && !shiftKey:
1822
+ case "ArrowLeft":
1823
+ case "ArrowRight":
1824
+ // handled by tree select
1825
+ break;
1826
+ case "ArrowDown":
1827
+ activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1828
+ event.preventDefault();
1829
+ break;
1830
+ default:
1831
+ const p = event.composedPath();
1832
+ if (p?.[0] instanceof HTMLInputElement) {
1833
+ return;
1834
+ }
1835
+ focusFilter.call(this);
1836
+ break;
1837
+ }
1854
1838
  }
1855
1839
 
1856
1840
  /**
@@ -1858,33 +1842,33 @@ function handleOptionKeyboardEvents(event) {
1858
1842
  * @return {string}
1859
1843
  */
1860
1844
  function getFilterMode() {
1861
- switch (this.getOption("filter.mode")) {
1862
- case FILTER_MODE_OPTIONS:
1863
- return FILTER_MODE_OPTIONS;
1864
- case FILTER_MODE_REMOTE:
1865
- return FILTER_MODE_REMOTE;
1866
- default:
1867
- return FILTER_MODE_DISABLED;
1868
- }
1845
+ switch (this.getOption("filter.mode")) {
1846
+ case FILTER_MODE_OPTIONS:
1847
+ return FILTER_MODE_OPTIONS;
1848
+ case FILTER_MODE_REMOTE:
1849
+ return FILTER_MODE_REMOTE;
1850
+ default:
1851
+ return FILTER_MODE_DISABLED;
1852
+ }
1869
1853
  }
1870
1854
 
1871
1855
  /**
1872
1856
  * @private
1873
1857
  */
1874
1858
  function blurFilter() {
1875
- if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) {
1876
- return;
1877
- }
1859
+ if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) {
1860
+ return;
1861
+ }
1878
1862
 
1879
- if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
1880
- return;
1881
- }
1863
+ if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
1864
+ return;
1865
+ }
1882
1866
 
1883
- this[popperFilterContainerElementSymbol].classList.remove("active");
1884
- this[popperFilterContainerElementSymbol].blur();
1867
+ this[popperFilterContainerElementSymbol].classList.remove("active");
1868
+ this[popperFilterContainerElementSymbol].blur();
1885
1869
 
1886
- this[inlineFilterElementSymbol].classList.remove("active");
1887
- this[inlineFilterElementSymbol].blur();
1870
+ this[inlineFilterElementSymbol].classList.remove("active");
1871
+ this[inlineFilterElementSymbol].blur();
1888
1872
  }
1889
1873
 
1890
1874
  /**
@@ -1892,28 +1876,25 @@ function blurFilter() {
1892
1876
  * @param focusOptions
1893
1877
  */
1894
1878
  function focusPopperFilter(focusOptions) {
1895
- this[popperFilterContainerElementSymbol].classList.remove("d-none");
1896
- this[popperFilterElementSymbol].classList.add("active");
1897
- this[inlineFilterElementSymbol].classList.remove("active");
1898
- this[inlineFilterElementSymbol].classList.add("d-none");
1899
-
1900
- if (!(this[popperFilterElementSymbol] instanceof HTMLElement)) {
1901
- addErrorAttribute(
1902
- this,
1903
- "Missing Popper Filter Element.",
1904
- );
1905
- return;
1906
- }
1907
-
1908
- // visibility is set to visible, because focus() does not work on invisible elements
1909
- // and the class definition is assigned later in the processing
1910
- setTimeout(() => {
1911
- if (focusOptions === undefined || focusOptions === null) {
1912
- this[popperFilterElementSymbol].focus();
1913
- } else {
1914
- this[popperFilterElementSymbol].focus(focusOptions);
1915
- }
1916
- }, 100);
1879
+ this[popperFilterContainerElementSymbol].classList.remove("d-none");
1880
+ this[popperFilterElementSymbol].classList.add("active");
1881
+ this[inlineFilterElementSymbol].classList.remove("active");
1882
+ this[inlineFilterElementSymbol].classList.add("d-none");
1883
+
1884
+ if (!(this[popperFilterElementSymbol] instanceof HTMLElement)) {
1885
+ addErrorAttribute(this, "Missing Popper Filter Element.");
1886
+ return;
1887
+ }
1888
+
1889
+ // visibility is set to visible, because focus() does not work on invisible elements
1890
+ // and the class definition is assigned later in the processing
1891
+ setTimeout(() => {
1892
+ if (focusOptions === undefined || focusOptions === null) {
1893
+ this[popperFilterElementSymbol].focus();
1894
+ } else {
1895
+ this[popperFilterElementSymbol].focus(focusOptions);
1896
+ }
1897
+ }, 100);
1917
1898
  }
1918
1899
 
1919
1900
  /**
@@ -1921,44 +1902,44 @@ function focusPopperFilter(focusOptions) {
1921
1902
  * @param focusOptions
1922
1903
  */
1923
1904
  function focusInlineFilter(focusOptions) {
1924
- const options = this.getOption("options");
1925
- if (
1926
- (!isArray(options) || options.length === 0) &&
1927
- getFilterMode.call(this) !== FILTER_MODE_REMOTE
1928
- ) {
1929
- return;
1930
- }
1931
-
1932
- this[popperFilterContainerElementSymbol].classList.add("d-none");
1933
- this[inlineFilterElementSymbol].classList.add("active");
1934
- this[inlineFilterElementSymbol].classList.remove("d-none");
1935
-
1936
- // visibility is set to visible, because focus() does not work on invisible elements
1937
- // and the class definition is assigned later in the processing
1938
- setTimeout(() => {
1939
- if (focusOptions === undefined || focusOptions === null) {
1940
- this[inlineFilterElementSymbol].focus();
1941
- } else {
1942
- this[inlineFilterElementSymbol].focus(focusOptions);
1943
- }
1944
- }, 100);
1905
+ const options = this.getOption("options");
1906
+ if (
1907
+ (!isArray(options) || options.length === 0) &&
1908
+ getFilterMode.call(this) !== FILTER_MODE_REMOTE
1909
+ ) {
1910
+ return;
1911
+ }
1912
+
1913
+ this[popperFilterContainerElementSymbol].classList.add("d-none");
1914
+ this[inlineFilterElementSymbol].classList.add("active");
1915
+ this[inlineFilterElementSymbol].classList.remove("d-none");
1916
+
1917
+ // visibility is set to visible, because focus() does not work on invisible elements
1918
+ // and the class definition is assigned later in the processing
1919
+ setTimeout(() => {
1920
+ if (focusOptions === undefined || focusOptions === null) {
1921
+ this[inlineFilterElementSymbol].focus();
1922
+ } else {
1923
+ this[inlineFilterElementSymbol].focus(focusOptions);
1924
+ }
1925
+ }, 100);
1945
1926
  }
1946
1927
 
1947
1928
  /**
1948
1929
  * @private
1949
1930
  */
1950
1931
  function focusFilter(focusOptions) {
1951
- if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
1952
- this[popperFilterContainerElementSymbol].classList.add("d-none");
1953
- this[inlineFilterElementSymbol].classList.add("d-none");
1954
- return;
1955
- }
1932
+ if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
1933
+ this[popperFilterContainerElementSymbol].classList.add("d-none");
1934
+ this[inlineFilterElementSymbol].classList.add("d-none");
1935
+ return;
1936
+ }
1956
1937
 
1957
- if (this.getOption("filter.position") === FILTER_POSITION_INLINE) {
1958
- return focusInlineFilter.call(this, focusOptions);
1959
- }
1938
+ if (this.getOption("filter.position") === FILTER_POSITION_INLINE) {
1939
+ return focusInlineFilter.call(this, focusOptions);
1940
+ }
1960
1941
 
1961
- return focusPopperFilter.call(this, focusOptions);
1942
+ return focusPopperFilter.call(this, focusOptions);
1962
1943
  }
1963
1944
 
1964
1945
  /**
@@ -1968,40 +1949,39 @@ function focusFilter(focusOptions) {
1968
1949
  * @throws {Error} unsupported type
1969
1950
  */
1970
1951
  function gatherState() {
1971
- const type = this.getOption("type");
1972
- if (["radio", "checkbox"].indexOf(type) === -1) {
1973
- throw new Error("unsupported type");
1974
- }
1975
-
1976
- if (!this.shadowRoot) {
1977
- throw new Error("no shadow-root is defined");
1978
- }
1979
-
1980
- const selection = [];
1981
- const elements = this.shadowRoot.querySelectorAll(
1982
- `input[type=${type}]:checked`,
1983
- );
1984
-
1985
- for (const e of elements) {
1986
- selection.push({
1987
- label: getSelectionLabel.call(this, e.value),
1988
- value: e.value,
1989
- });
1990
- }
1991
-
1992
- setSelection
1993
- .call(this, selection)
1994
- .then(() => {
1995
- })
1996
- .catch((e) => {
1997
- addErrorAttribute(this, e);
1998
- });
1999
-
2000
- if (this.getOption("features.closeOnSelect") === true) {
2001
- toggle.call(this);
2002
- }
2003
-
2004
- return this;
1952
+ const type = this.getOption("type");
1953
+ if (["radio", "checkbox"].indexOf(type) === -1) {
1954
+ throw new Error("unsupported type");
1955
+ }
1956
+
1957
+ if (!this.shadowRoot) {
1958
+ throw new Error("no shadow-root is defined");
1959
+ }
1960
+
1961
+ const selection = [];
1962
+ const elements = this.shadowRoot.querySelectorAll(
1963
+ `input[type=${type}]:checked`,
1964
+ );
1965
+
1966
+ for (const e of elements) {
1967
+ selection.push({
1968
+ label: getSelectionLabel.call(this, e.value),
1969
+ value: e.value,
1970
+ });
1971
+ }
1972
+
1973
+ setSelection
1974
+ .call(this, selection)
1975
+ .then(() => {})
1976
+ .catch((e) => {
1977
+ addErrorAttribute(this, e);
1978
+ });
1979
+
1980
+ if (this.getOption("features.closeOnSelect") === true) {
1981
+ toggle.call(this);
1982
+ }
1983
+
1984
+ return this;
2005
1985
  }
2006
1986
 
2007
1987
  /**
@@ -2010,121 +1990,120 @@ function gatherState() {
2010
1990
  * @throws {Error} unsupported type
2011
1991
  */
2012
1992
  function clearSelection() {
2013
- const type = this.getOption("type");
2014
- if (["radio", "checkbox"].indexOf(type) === -1) {
2015
- throw new Error("unsupported type");
2016
- }
2017
-
2018
- if (!this.shadowRoot) {
2019
- throw new Error("no shadow-root is defined");
2020
- }
2021
-
2022
- setSelection
2023
- .call(this, [])
2024
- .then(() => {
2025
- })
2026
- .catch((e) => {
2027
- addErrorAttribute(this, e);
2028
- });
1993
+ const type = this.getOption("type");
1994
+ if (["radio", "checkbox"].indexOf(type) === -1) {
1995
+ throw new Error("unsupported type");
1996
+ }
1997
+
1998
+ if (!this.shadowRoot) {
1999
+ throw new Error("no shadow-root is defined");
2000
+ }
2001
+
2002
+ setSelection
2003
+ .call(this, [])
2004
+ .then(() => {})
2005
+ .catch((e) => {
2006
+ addErrorAttribute(this, e);
2007
+ });
2029
2008
  }
2030
2009
 
2031
2010
  /**
2032
2011
  * @private
2033
2012
  */
2034
2013
  function areOptionsAvailableAndInit() {
2035
- // prevent multiple calls
2036
- if (this[areOptionsAvailableAndInitSymbol] === undefined) {
2037
- this[areOptionsAvailableAndInitSymbol] = 0;
2038
- }
2039
-
2040
- if (this[areOptionsAvailableAndInitSymbol] > 0) {
2041
- this[areOptionsAvailableAndInitSymbol]--;
2042
- return true;
2043
- }
2044
-
2045
- this[areOptionsAvailableAndInitSymbol]++;
2046
-
2047
- const options = this.getOption("options");
2048
-
2049
- if (
2050
- options === undefined ||
2051
- options === null ||
2052
- (isArray(options) && options.length === 0)
2053
- ) {
2054
- setStatusOrRemoveBadges.call(this, "empty");
2055
-
2056
- // hide.call(this);
2057
-
2058
- let msg = this.getOption("labels.no-options-available");
2059
-
2060
- if (
2061
- this.getOption("url") !== null &&
2062
- this.getOption("features.lazyLoad") === true &&
2063
- this[lazyLoadDoneSymbol] !== true
2064
- ) {
2065
- msg = this.getOption("labels.click-to-load-options");
2066
- }
2067
-
2068
- this.setOption("messages.control", msg);
2069
- this.setOption("messages.summary", "");
2070
-
2071
- if (this.getOption("features.emptyValueIfNoOptions") === true) {
2072
- this.value = "";
2073
- }
2074
- addErrorAttribute(this, "No options available.");
2075
- return false;
2076
- }
2077
-
2078
- const selections = this.getOption("selection");
2079
- if (
2080
- selections === undefined ||
2081
- selections === null ||
2082
- selections.length === 0
2083
- ) {
2084
- this.setOption(
2085
- "messages.control",
2086
- this.getOption("labels.select-an-option"),
2087
- );
2088
- } else {
2089
- this.setOption("messages.control", "");
2090
- }
2091
-
2092
- this.setOption("messages.summary", setSummaryAndControlText.call(this));
2093
-
2094
- let updated = false;
2095
- let valueCounter = 1;
2096
- for (const option of options) {
2097
- if (option?.visibility === undefined) {
2098
- option.visibility = "visible";
2099
- updated = true;
2100
- }
2101
-
2102
- if (option?.value === undefined && option?.label === undefined) {
2103
- option.value = `${valueCounter++}`;
2104
- option.label = option.value;
2105
- updated = true;
2106
- continue;
2107
- }
2108
-
2109
- if (option?.value === undefined) {
2110
- option.value = option.label;
2111
- updated = true;
2112
- }
2113
-
2114
- if (option?.label === undefined) {
2115
- option.label = option.value;
2116
- updated = true;
2117
- }
2118
- }
2119
-
2120
- if (updated) {
2121
- this.setOption("options", options);
2122
- }
2123
-
2124
- setStatusOrRemoveBadges.call(this);
2125
-
2126
- removeErrorAttribute(this, "No options available.");
2127
- return true;
2014
+ // prevent multiple calls
2015
+ if (this[areOptionsAvailableAndInitSymbol] === undefined) {
2016
+ this[areOptionsAvailableAndInitSymbol] = 0;
2017
+ }
2018
+
2019
+ if (this[areOptionsAvailableAndInitSymbol] > 0) {
2020
+ this[areOptionsAvailableAndInitSymbol]--;
2021
+ return true;
2022
+ }
2023
+
2024
+ this[areOptionsAvailableAndInitSymbol]++;
2025
+
2026
+ const options = this.getOption("options");
2027
+
2028
+ if (
2029
+ options === undefined ||
2030
+ options === null ||
2031
+ (isArray(options) && options.length === 0)
2032
+ ) {
2033
+ setStatusOrRemoveBadges.call(this, "empty");
2034
+
2035
+ // hide.call(this);
2036
+
2037
+ let msg = this.getOption("labels.no-options-available");
2038
+
2039
+ if (
2040
+ this.getOption("url") !== null &&
2041
+ this.getOption("features.lazyLoad") === true &&
2042
+ this[lazyLoadDoneSymbol] !== true
2043
+ ) {
2044
+ msg = this.getOption("labels.click-to-load-options");
2045
+ }
2046
+
2047
+ this.setOption("messages.control", msg);
2048
+ this.setOption("messages.summary", "");
2049
+
2050
+ if (this.getOption("features.emptyValueIfNoOptions") === true) {
2051
+ this.value = "";
2052
+ }
2053
+ addErrorAttribute(this, "No options available.");
2054
+ return false;
2055
+ }
2056
+
2057
+ const selections = this.getOption("selection");
2058
+ if (
2059
+ selections === undefined ||
2060
+ selections === null ||
2061
+ selections.length === 0
2062
+ ) {
2063
+ this.setOption(
2064
+ "messages.control",
2065
+ this.getOption("labels.select-an-option"),
2066
+ );
2067
+ } else {
2068
+ this.setOption("messages.control", "");
2069
+ }
2070
+
2071
+ this.setOption("messages.summary", setSummaryAndControlText.call(this));
2072
+
2073
+ let updated = false;
2074
+ let valueCounter = 1;
2075
+ for (const option of options) {
2076
+ if (option?.visibility === undefined) {
2077
+ option.visibility = "visible";
2078
+ updated = true;
2079
+ }
2080
+
2081
+ if (option?.value === undefined && option?.label === undefined) {
2082
+ option.value = `${valueCounter++}`;
2083
+ option.label = option.value;
2084
+ updated = true;
2085
+ continue;
2086
+ }
2087
+
2088
+ if (option?.value === undefined) {
2089
+ option.value = option.label;
2090
+ updated = true;
2091
+ }
2092
+
2093
+ if (option?.label === undefined) {
2094
+ option.label = option.value;
2095
+ updated = true;
2096
+ }
2097
+ }
2098
+
2099
+ if (updated) {
2100
+ this.setOption("options", options);
2101
+ }
2102
+
2103
+ setStatusOrRemoveBadges.call(this);
2104
+
2105
+ removeErrorAttribute(this, "No options available.");
2106
+ return true;
2128
2107
  }
2129
2108
 
2130
2109
  /**
@@ -2132,30 +2111,30 @@ function areOptionsAvailableAndInit() {
2132
2111
  * @throws {Error} no shadow-root is defined
2133
2112
  */
2134
2113
  function checkOptionState() {
2135
- if (!this.shadowRoot) {
2136
- throw new Error("no shadow-root is defined");
2137
- }
2138
-
2139
- const elements = this.shadowRoot.querySelectorAll(
2140
- `[${ATTRIBUTE_ROLE}=option] input`,
2141
- );
2142
-
2143
- let selection = this.getOption("selection");
2144
- if (!isArray(selection)) {
2145
- selection = [];
2146
- }
2147
-
2148
- const checkedValues = selection.map((a) => {
2149
- return a.value;
2150
- });
2151
-
2152
- for (const e of elements) {
2153
- if (checkedValues.indexOf(e.value) !== -1) {
2154
- if (e.checked !== true) e.checked = true;
2155
- } else {
2156
- if (e.checked !== false) e.checked = false;
2157
- }
2158
- }
2114
+ if (!this.shadowRoot) {
2115
+ throw new Error("no shadow-root is defined");
2116
+ }
2117
+
2118
+ const elements = this.shadowRoot.querySelectorAll(
2119
+ `[${ATTRIBUTE_ROLE}=option] input`,
2120
+ );
2121
+
2122
+ let selection = this.getOption("selection");
2123
+ if (!isArray(selection)) {
2124
+ selection = [];
2125
+ }
2126
+
2127
+ const checkedValues = selection.map((a) => {
2128
+ return a.value;
2129
+ });
2130
+
2131
+ for (const e of elements) {
2132
+ if (checkedValues.indexOf(e.value) !== -1) {
2133
+ if (e.checked !== true) e.checked = true;
2134
+ } else {
2135
+ if (e.checked !== false) e.checked = false;
2136
+ }
2137
+ }
2159
2138
  }
2160
2139
 
2161
2140
  /**
@@ -2164,42 +2143,41 @@ function checkOptionState() {
2164
2143
  * @return {Object}
2165
2144
  */
2166
2145
  function convertValueToSelection(value) {
2167
- const selection = [];
2168
-
2169
- if (isString(value)) {
2170
- value = value
2171
- .split(",")
2172
- .map((a) => {
2173
- return a.trim();
2174
- })
2175
- .filter((a) => {
2176
- return a !== "";
2177
- });
2178
-
2179
- }
2180
-
2181
- if (isString(value) || isInteger(value)) {
2182
- selection.push({
2183
- label: getSelectionLabel.call(this, value),
2184
- value: value,
2185
- });
2186
- } else if (isArray(value)) {
2187
- for (const v of value) {
2188
- selection.push({
2189
- label: getSelectionLabel.call(this, v),
2190
- value: v,
2191
- });
2192
- }
2193
-
2194
- value = value.join(",");
2195
- } else {
2196
- throw new Error("unsupported type");
2197
- }
2198
-
2199
- return {
2200
- selection: selection,
2201
- value: value,
2202
- };
2146
+ const selection = [];
2147
+
2148
+ if (isString(value)) {
2149
+ value = value
2150
+ .split(",")
2151
+ .map((a) => {
2152
+ return a.trim();
2153
+ })
2154
+ .filter((a) => {
2155
+ return a !== "";
2156
+ });
2157
+ }
2158
+
2159
+ if (isString(value) || isInteger(value)) {
2160
+ selection.push({
2161
+ label: getSelectionLabel.call(this, value),
2162
+ value: value,
2163
+ });
2164
+ } else if (isArray(value)) {
2165
+ for (const v of value) {
2166
+ selection.push({
2167
+ label: getSelectionLabel.call(this, v),
2168
+ value: v,
2169
+ });
2170
+ }
2171
+
2172
+ value = value.join(",");
2173
+ } else {
2174
+ throw new Error("unsupported type");
2175
+ }
2176
+
2177
+ return {
2178
+ selection: selection,
2179
+ value: value,
2180
+ };
2203
2181
  }
2204
2182
 
2205
2183
  /**
@@ -2208,25 +2186,25 @@ function convertValueToSelection(value) {
2208
2186
  * @return {string}
2209
2187
  */
2210
2188
  function convertSelectionToValue(selection) {
2211
- const value = [];
2212
-
2213
- if (isArray(selection)) {
2214
- for (const obj of selection) {
2215
- const v = obj?.["value"];
2216
- if (v !== undefined) value.push(`${v}`);
2217
- }
2218
- }
2219
-
2220
- if (value.length === 0) {
2221
- return "";
2222
- } else if (value.length === 1) {
2223
- const v = value.pop();
2224
- if (v === undefined) return "";
2225
- if (v === null) return "";
2226
- return `${v}`;
2227
- }
2228
-
2229
- return value.join(",");
2189
+ const value = [];
2190
+
2191
+ if (isArray(selection)) {
2192
+ for (const obj of selection) {
2193
+ const v = obj?.["value"];
2194
+ if (v !== undefined) value.push(`${v}`);
2195
+ }
2196
+ }
2197
+
2198
+ if (value.length === 0) {
2199
+ return "";
2200
+ } else if (value.length === 1) {
2201
+ const v = value.pop();
2202
+ if (v === undefined) return "";
2203
+ if (v === null) return "";
2204
+ return `${v}`;
2205
+ }
2206
+
2207
+ return value.join(",");
2230
2208
  }
2231
2209
 
2232
2210
  /**
@@ -2236,76 +2214,76 @@ function convertSelectionToValue(selection) {
2236
2214
  * @throws {Error} no shadow-root is defined
2237
2215
  */
2238
2216
  function setSelection(selection) {
2239
- if (isString(selection) || isInteger(selection)) {
2240
- const result = convertValueToSelection.call(this, selection);
2241
- selection = result?.selection;
2242
- } else if (selection === undefined || selection === null) {
2243
- selection = [];
2244
- }
2245
-
2246
- validateArray(selection);
2247
-
2248
- for (let i = 0; i < selection.length; i++) {
2249
- let l = getSelectionLabel.call(this, selection[i].value);
2250
- if (l === selection[i].value) {
2251
- l = selection[i].label;
2252
- }
2253
-
2254
- selection[i] = {
2255
- label: l,
2256
- value: selection[i].value,
2257
- };
2258
- }
2259
-
2260
- this.setOption("selection", selection);
2261
- checkOptionState.call(this);
2262
- setSummaryAndControlText.call(this);
2263
-
2264
- try {
2265
- this?.setFormValue(this.value);
2266
- } catch (e) {
2267
- addErrorAttribute(this, e);
2268
- }
2269
-
2270
- fireCustomEvent(this, "monster-selected", {
2271
- selection,
2272
- });
2273
-
2274
- fireEvent(this, "change");
2275
-
2276
- return new Processing(() => {
2277
- const CLASSNAME = "selected";
2278
-
2279
- if (!this.shadowRoot) {
2280
- throw new Error("no shadow-root is defined");
2281
- }
2282
-
2283
- const notSelected = this.shadowRoot.querySelectorAll(":not(:checked)");
2284
-
2285
- if (notSelected) {
2286
- notSelected.forEach((node) => {
2287
- const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`);
2288
- if (parent) {
2289
- parent.classList.remove(CLASSNAME);
2290
- }
2291
- });
2292
- }
2293
-
2294
- const selected = this.shadowRoot.querySelectorAll(":checked");
2295
-
2296
- if (selected) {
2297
- selected.forEach((node) => {
2298
- const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`);
2299
- if (parent) {
2300
- parent.classList.add(CLASSNAME);
2301
- }
2302
- });
2303
- }
2304
- })
2305
- .run()
2306
- .catch((e) => {
2307
- addErrorAttribute(this, e);
2308
- });
2217
+ if (isString(selection) || isInteger(selection)) {
2218
+ const result = convertValueToSelection.call(this, selection);
2219
+ selection = result?.selection;
2220
+ } else if (selection === undefined || selection === null) {
2221
+ selection = [];
2222
+ }
2223
+
2224
+ validateArray(selection);
2225
+
2226
+ for (let i = 0; i < selection.length; i++) {
2227
+ let l = getSelectionLabel.call(this, selection[i].value);
2228
+ if (l === selection[i].value) {
2229
+ l = selection[i].label;
2230
+ }
2231
+
2232
+ selection[i] = {
2233
+ label: l,
2234
+ value: selection[i].value,
2235
+ };
2236
+ }
2237
+
2238
+ this.setOption("selection", selection);
2239
+ checkOptionState.call(this);
2240
+ setSummaryAndControlText.call(this);
2241
+
2242
+ try {
2243
+ this?.setFormValue(this.value);
2244
+ } catch (e) {
2245
+ addErrorAttribute(this, e);
2246
+ }
2247
+
2248
+ fireCustomEvent(this, "monster-selected", {
2249
+ selection,
2250
+ });
2251
+
2252
+ fireEvent(this, "change");
2253
+
2254
+ return new Processing(() => {
2255
+ const CLASSNAME = "selected";
2256
+
2257
+ if (!this.shadowRoot) {
2258
+ throw new Error("no shadow-root is defined");
2259
+ }
2260
+
2261
+ const notSelected = this.shadowRoot.querySelectorAll(":not(:checked)");
2262
+
2263
+ if (notSelected) {
2264
+ notSelected.forEach((node) => {
2265
+ const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`);
2266
+ if (parent) {
2267
+ parent.classList.remove(CLASSNAME);
2268
+ }
2269
+ });
2270
+ }
2271
+
2272
+ const selected = this.shadowRoot.querySelectorAll(":checked");
2273
+
2274
+ if (selected) {
2275
+ selected.forEach((node) => {
2276
+ const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`);
2277
+ if (parent) {
2278
+ parent.classList.add(CLASSNAME);
2279
+ }
2280
+ });
2281
+ }
2282
+ })
2283
+ .run()
2284
+ .catch((e) => {
2285
+ addErrorAttribute(this, e);
2286
+ });
2309
2287
  }
2310
2288
 
2311
2289
  /**
@@ -2316,139 +2294,139 @@ function setSelection(selection) {
2316
2294
  * @throws {TypeError} unsupported response
2317
2295
  */
2318
2296
  function fetchData(url) {
2319
- const self = this;
2320
- if (!url) url = this.getOption("url");
2321
- if (!url) return Promise.resolve();
2322
-
2323
- const fetchOptions = this.getOption("fetch", {});
2324
-
2325
- let delayWatch = false;
2326
-
2327
- // if fetch short time, do not show loading badge, because of flickering
2328
- requestAnimationFrame(() => {
2329
- if (delayWatch === true) return;
2330
- setStatusOrRemoveBadges.call(this, "loading");
2331
- delayWatch = true;
2332
- });
2333
-
2334
- url = formatURL.call(this, url);
2335
-
2336
- self[isLoadingSymbol] = true;
2337
- const global = getGlobal();
2338
- return global
2339
- .fetch(url, fetchOptions)
2340
- .then((response) => {
2341
- self[isLoadingSymbol] = false;
2342
- delayWatch = true;
2343
- const contentType = response.headers.get("content-type");
2344
- if (contentType && contentType.indexOf("application/json") !== -1) {
2345
- return response.text();
2346
- }
2347
-
2348
- throw new TypeError(`unsupported response ${contentType}`);
2349
- })
2350
- .then((text) => {
2351
- try {
2352
- return Promise.resolve(JSON.parse(String(text)));
2353
- } catch (e) {
2354
- throw new TypeError("the result cannot be parsed, check the URL");
2355
- }
2356
- })
2357
- .catch((e) => {
2358
- self[isLoadingSymbol] = false;
2359
- delayWatch = true;
2360
- throw e;
2361
- });
2297
+ const self = this;
2298
+ if (!url) url = this.getOption("url");
2299
+ if (!url) return Promise.resolve();
2300
+
2301
+ const fetchOptions = this.getOption("fetch", {});
2302
+
2303
+ let delayWatch = false;
2304
+
2305
+ // if fetch short time, do not show loading badge, because of flickering
2306
+ requestAnimationFrame(() => {
2307
+ if (delayWatch === true) return;
2308
+ setStatusOrRemoveBadges.call(this, "loading");
2309
+ delayWatch = true;
2310
+ });
2311
+
2312
+ url = formatURL.call(this, url);
2313
+
2314
+ self[isLoadingSymbol] = true;
2315
+ const global = getGlobal();
2316
+ return global
2317
+ .fetch(url, fetchOptions)
2318
+ .then((response) => {
2319
+ self[isLoadingSymbol] = false;
2320
+ delayWatch = true;
2321
+ const contentType = response.headers.get("content-type");
2322
+ if (contentType && contentType.indexOf("application/json") !== -1) {
2323
+ return response.text();
2324
+ }
2325
+
2326
+ throw new TypeError(`unsupported response ${contentType}`);
2327
+ })
2328
+ .then((text) => {
2329
+ try {
2330
+ return Promise.resolve(JSON.parse(String(text)));
2331
+ } catch (e) {
2332
+ throw new TypeError("the result cannot be parsed, check the URL");
2333
+ }
2334
+ })
2335
+ .catch((e) => {
2336
+ self[isLoadingSymbol] = false;
2337
+ delayWatch = true;
2338
+ throw e;
2339
+ });
2362
2340
  }
2363
2341
 
2364
2342
  /**
2365
2343
  * @private
2366
2344
  */
2367
2345
  function hide() {
2368
- this[popperElementSymbol].style.display = "none";
2369
- setStatusOrRemoveBadges.call(this, "closed");
2370
- removeAttributeToken(this[controlElementSymbol], "class", "open");
2346
+ this[popperElementSymbol].style.display = "none";
2347
+ setStatusOrRemoveBadges.call(this, "closed");
2348
+ removeAttributeToken(this[controlElementSymbol], "class", "open");
2371
2349
  }
2372
2350
 
2373
2351
  /**
2374
2352
  * @private
2375
2353
  */
2376
2354
  function show() {
2377
- if (this.getOption("disabled", undefined) === true) {
2378
- return;
2379
- }
2380
-
2381
- if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
2382
- return;
2383
- }
2384
-
2385
- focusFilter.call(this);
2386
-
2387
- const lazyLoadFlag =
2388
- this.getOption("features.lazyLoad") && this[lazyLoadDoneSymbol] !== true;
2389
-
2390
- if (lazyLoadFlag === true) {
2391
- this[lazyLoadDoneSymbol] = true;
2392
- setStatusOrRemoveBadges.call(this, "loading");
2393
-
2394
- new Processing(200, () => {
2395
- this.fetch()
2396
- .then(() => {
2397
- checkOptionState.call(this);
2398
- requestAnimationFrame(() => {
2399
- show.call(this);
2400
- });
2401
- })
2402
- .catch((e) => {
2403
- addErrorAttribute(this, e);
2404
- setStatusOrRemoveBadges.call(this, "error");
2405
- });
2406
- })
2407
- .run()
2408
- .catch((e) => {
2409
- addErrorAttribute(this, e);
2410
- setStatusOrRemoveBadges.call(this, "error");
2411
- });
2412
-
2413
- return;
2414
- }
2415
-
2416
- const hasPopperFilterFlag =
2417
- this.getOption("filter.position") === FILTER_POSITION_POPPER &&
2418
- getFilterMode.call(this) !== FILTER_MODE_DISABLED;
2419
-
2420
- const options = getOptionElements.call(this);
2421
- if (options.length === 0 && hasPopperFilterFlag === false) {
2422
- return;
2423
- }
2424
-
2425
- this[popperElementSymbol].style.visibility = "hidden";
2426
- this[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK;
2427
- setStatusOrRemoveBadges.call(this, "open");
2428
-
2429
- addAttributeToken(this[controlElementSymbol], "class", "open");
2430
-
2431
- new Processing(() => {
2432
- calcAndSetOptionsDimension.call(this);
2433
- focusFilter.call(this);
2434
- this[popperElementSymbol].style.removeProperty("visibility");
2435
- updatePopper.call(this);
2436
- })
2437
- .run()
2438
- .catch((e) => {
2439
- addErrorAttribute(this, e);
2440
- });
2355
+ if (this.getOption("disabled", undefined) === true) {
2356
+ return;
2357
+ }
2358
+
2359
+ if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
2360
+ return;
2361
+ }
2362
+
2363
+ focusFilter.call(this);
2364
+
2365
+ const lazyLoadFlag =
2366
+ this.getOption("features.lazyLoad") && this[lazyLoadDoneSymbol] !== true;
2367
+
2368
+ if (lazyLoadFlag === true) {
2369
+ this[lazyLoadDoneSymbol] = true;
2370
+ setStatusOrRemoveBadges.call(this, "loading");
2371
+
2372
+ new Processing(200, () => {
2373
+ this.fetch()
2374
+ .then(() => {
2375
+ checkOptionState.call(this);
2376
+ requestAnimationFrame(() => {
2377
+ show.call(this);
2378
+ });
2379
+ })
2380
+ .catch((e) => {
2381
+ addErrorAttribute(this, e);
2382
+ setStatusOrRemoveBadges.call(this, "error");
2383
+ });
2384
+ })
2385
+ .run()
2386
+ .catch((e) => {
2387
+ addErrorAttribute(this, e);
2388
+ setStatusOrRemoveBadges.call(this, "error");
2389
+ });
2390
+
2391
+ return;
2392
+ }
2393
+
2394
+ const hasPopperFilterFlag =
2395
+ this.getOption("filter.position") === FILTER_POSITION_POPPER &&
2396
+ getFilterMode.call(this) !== FILTER_MODE_DISABLED;
2397
+
2398
+ const options = getOptionElements.call(this);
2399
+ if (options.length === 0 && hasPopperFilterFlag === false) {
2400
+ return;
2401
+ }
2402
+
2403
+ this[popperElementSymbol].style.visibility = "hidden";
2404
+ this[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK;
2405
+ setStatusOrRemoveBadges.call(this, "open");
2406
+
2407
+ addAttributeToken(this[controlElementSymbol], "class", "open");
2408
+
2409
+ new Processing(() => {
2410
+ calcAndSetOptionsDimension.call(this);
2411
+ focusFilter.call(this);
2412
+ this[popperElementSymbol].style.removeProperty("visibility");
2413
+ updatePopper.call(this);
2414
+ })
2415
+ .run()
2416
+ .catch((e) => {
2417
+ addErrorAttribute(this, e);
2418
+ });
2441
2419
  }
2442
2420
 
2443
2421
  /**
2444
2422
  * @private
2445
2423
  */
2446
2424
  function toggle() {
2447
- if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
2448
- hide.call(this);
2449
- } else {
2450
- show.call(this);
2451
- }
2425
+ if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
2426
+ hide.call(this);
2427
+ } else {
2428
+ show.call(this);
2429
+ }
2452
2430
  }
2453
2431
 
2454
2432
  /**
@@ -2457,188 +2435,188 @@ function toggle() {
2457
2435
  * @fires monster-selection-cleared
2458
2436
  */
2459
2437
  function initEventHandler() {
2460
- const self = this;
2461
-
2462
- /**
2463
- * @param {Event} event
2464
- */
2465
- self[clearOptionEventHandler] = (event) => {
2466
- const element = findTargetElementFromEvent(
2467
- event,
2468
- ATTRIBUTE_ROLE,
2469
- "remove-badge",
2470
- );
2471
-
2472
- if (element instanceof HTMLElement) {
2473
- const badge = findClosestByAttribute(element, ATTRIBUTE_ROLE, "badge");
2474
- if (badge instanceof HTMLElement) {
2475
- const value = badge.getAttribute(`${ATTRIBUTE_PREFIX}value`);
2476
-
2477
- let selection = self.getOption("selection");
2478
- selection = selection.filter((b) => {
2479
- return value !== b.value;
2480
- });
2481
-
2482
- setSelection
2483
- .call(self, selection)
2484
- .then(() => {
2485
- fireCustomEvent(self, "monster-selection-removed", {
2486
- value,
2487
- });
2488
- })
2489
- .catch((e) => {
2490
- addErrorAttribute(self, e);
2491
- });
2492
- }
2493
- }
2494
- };
2495
-
2496
- /**
2497
- * @param {Event} event
2498
- */
2499
- self[closeEventHandler] = (event) => {
2500
- const path = event.composedPath();
2501
-
2502
- for (const [, element] of Object.entries(path)) {
2503
- if (element === self) {
2504
- return;
2505
- }
2506
- }
2507
- hide.call(self);
2508
- };
2509
-
2510
- /**
2511
- * @param {Event} event
2512
- */
2513
- self[inputEventHandler] = (event) => {
2514
- const path = event.composedPath();
2515
- const element = path?.[0];
2516
-
2517
- if (element instanceof HTMLElement) {
2518
- if (
2519
- element.hasAttribute(ATTRIBUTE_ROLE) &&
2520
- element.getAttribute(ATTRIBUTE_ROLE) === "option-control"
2521
- ) {
2522
- fireCustomEvent(self, "monster-change", {
2523
- type: event.type,
2524
- value: element.value,
2525
- checked: element.checked,
2526
- });
2527
- } else if (
2528
- element.hasAttribute(ATTRIBUTE_ROLE) &&
2529
- element.getAttribute(ATTRIBUTE_ROLE) === "filter"
2530
- ) {
2531
- }
2532
- }
2533
- };
2534
-
2535
- /**
2536
- * @param {Event} event
2537
- */
2538
- self[changeEventHandler] = (event) => {
2539
- gatherState.call(self);
2540
- fireCustomEvent(self, "monster-changed", event?.detail);
2541
- };
2542
-
2543
- self[keyEventHandler] = (event) => {
2544
- const path = event.composedPath();
2545
- const element = path.shift();
2546
-
2547
- let role;
2548
-
2549
- if (element instanceof HTMLElement) {
2550
- if (element.hasAttribute(ATTRIBUTE_ROLE)) {
2551
- role = element.getAttribute(ATTRIBUTE_ROLE);
2552
- } else if (element === this) {
2553
- show.call(this);
2554
- // focusFilter.call(self);
2555
- } else {
2556
- const e = element.closest(`[${ATTRIBUTE_ROLE}]`);
2557
- if (e instanceof HTMLElement && e.hasAttribute(ATTRIBUTE_ROLE)) {
2558
- role = e.getAttribute(ATTRIBUTE_ROLE);
2559
- }
2560
- }
2561
- } else {
2562
- return;
2563
- }
2564
-
2565
- switch (role) {
2566
- case "filter":
2567
- handleFilterKeyboardEvents.call(self, event);
2568
- break;
2569
- case "option-label":
2570
- case "option-control":
2571
- case "option":
2572
- handleOptionKeyboardEvents.call(self, event);
2573
- break;
2574
- case "control":
2575
- case "toggle":
2576
- handleToggleKeyboardEvents.call(self, event);
2577
- break;
2578
- }
2579
- };
2580
-
2581
- const types = self.getOption("toggleEventType", ["click"]);
2582
-
2583
- for (const [, type] of Object.entries(types)) {
2584
- self[controlElementSymbol]
2585
- .querySelector(`[${ATTRIBUTE_ROLE}="container"]`)
2586
- .addEventListener(type, function (event) {
2587
- const element = findTargetElementFromEvent(
2588
- event,
2589
- ATTRIBUTE_ROLE,
2590
- "remove-badge",
2591
- );
2592
- if (element instanceof HTMLElement) {
2593
- return;
2594
- }
2595
-
2596
- toggle.call(self);
2597
- });
2598
-
2599
- self[controlElementSymbol]
2600
- .querySelector(`[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`)
2601
- .addEventListener(type, function (event) {
2602
- if (self.getOption("disabled", undefined) === true) {
2603
- return;
2604
- }
2605
-
2606
- const path = event.composedPath();
2607
- const element = path?.[0];
2608
- if (element instanceof HTMLElement) {
2609
- const control = element.closest(
2610
- `[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`,
2611
- );
2612
- if (control instanceof HTMLElement) {
2613
- if (control.classList.contains("clear")) {
2614
- clearSelection.call(self);
2615
-
2616
- fireCustomEvent(self, "monster-selection-cleared", {});
2617
- } else {
2618
- const element = findTargetElementFromEvent(
2619
- event,
2620
- ATTRIBUTE_ROLE,
2621
- "remove-badge",
2622
- );
2623
- if (element instanceof HTMLElement) {
2624
- return;
2625
- }
2626
-
2627
- toggle.call(self);
2628
- }
2629
- }
2630
- }
2631
- });
2632
-
2633
- // badge, selection
2634
- self.addEventListener(type, self[clearOptionEventHandler]);
2635
- }
2636
-
2637
- self.addEventListener("monster-change", self[changeEventHandler]);
2638
- self.addEventListener("input", self[inputEventHandler]);
2639
- self.addEventListener("keydown", self[keyEventHandler]);
2640
-
2641
- return self;
2438
+ const self = this;
2439
+
2440
+ /**
2441
+ * @param {Event} event
2442
+ */
2443
+ self[clearOptionEventHandler] = (event) => {
2444
+ const element = findTargetElementFromEvent(
2445
+ event,
2446
+ ATTRIBUTE_ROLE,
2447
+ "remove-badge",
2448
+ );
2449
+
2450
+ if (element instanceof HTMLElement) {
2451
+ const badge = findClosestByAttribute(element, ATTRIBUTE_ROLE, "badge");
2452
+ if (badge instanceof HTMLElement) {
2453
+ const value = badge.getAttribute(`${ATTRIBUTE_PREFIX}value`);
2454
+
2455
+ let selection = self.getOption("selection");
2456
+ selection = selection.filter((b) => {
2457
+ return value !== b.value;
2458
+ });
2459
+
2460
+ setSelection
2461
+ .call(self, selection)
2462
+ .then(() => {
2463
+ fireCustomEvent(self, "monster-selection-removed", {
2464
+ value,
2465
+ });
2466
+ })
2467
+ .catch((e) => {
2468
+ addErrorAttribute(self, e);
2469
+ });
2470
+ }
2471
+ }
2472
+ };
2473
+
2474
+ /**
2475
+ * @param {Event} event
2476
+ */
2477
+ self[closeEventHandler] = (event) => {
2478
+ const path = event.composedPath();
2479
+
2480
+ for (const [, element] of Object.entries(path)) {
2481
+ if (element === self) {
2482
+ return;
2483
+ }
2484
+ }
2485
+ hide.call(self);
2486
+ };
2487
+
2488
+ /**
2489
+ * @param {Event} event
2490
+ */
2491
+ self[inputEventHandler] = (event) => {
2492
+ const path = event.composedPath();
2493
+ const element = path?.[0];
2494
+
2495
+ if (element instanceof HTMLElement) {
2496
+ if (
2497
+ element.hasAttribute(ATTRIBUTE_ROLE) &&
2498
+ element.getAttribute(ATTRIBUTE_ROLE) === "option-control"
2499
+ ) {
2500
+ fireCustomEvent(self, "monster-change", {
2501
+ type: event.type,
2502
+ value: element.value,
2503
+ checked: element.checked,
2504
+ });
2505
+ } else if (
2506
+ element.hasAttribute(ATTRIBUTE_ROLE) &&
2507
+ element.getAttribute(ATTRIBUTE_ROLE) === "filter"
2508
+ ) {
2509
+ }
2510
+ }
2511
+ };
2512
+
2513
+ /**
2514
+ * @param {Event} event
2515
+ */
2516
+ self[changeEventHandler] = (event) => {
2517
+ gatherState.call(self);
2518
+ fireCustomEvent(self, "monster-changed", event?.detail);
2519
+ };
2520
+
2521
+ self[keyEventHandler] = (event) => {
2522
+ const path = event.composedPath();
2523
+ const element = path.shift();
2524
+
2525
+ let role;
2526
+
2527
+ if (element instanceof HTMLElement) {
2528
+ if (element.hasAttribute(ATTRIBUTE_ROLE)) {
2529
+ role = element.getAttribute(ATTRIBUTE_ROLE);
2530
+ } else if (element === this) {
2531
+ show.call(this);
2532
+ // focusFilter.call(self);
2533
+ } else {
2534
+ const e = element.closest(`[${ATTRIBUTE_ROLE}]`);
2535
+ if (e instanceof HTMLElement && e.hasAttribute(ATTRIBUTE_ROLE)) {
2536
+ role = e.getAttribute(ATTRIBUTE_ROLE);
2537
+ }
2538
+ }
2539
+ } else {
2540
+ return;
2541
+ }
2542
+
2543
+ switch (role) {
2544
+ case "filter":
2545
+ handleFilterKeyboardEvents.call(self, event);
2546
+ break;
2547
+ case "option-label":
2548
+ case "option-control":
2549
+ case "option":
2550
+ handleOptionKeyboardEvents.call(self, event);
2551
+ break;
2552
+ case "control":
2553
+ case "toggle":
2554
+ handleToggleKeyboardEvents.call(self, event);
2555
+ break;
2556
+ }
2557
+ };
2558
+
2559
+ const types = self.getOption("toggleEventType", ["click"]);
2560
+
2561
+ for (const [, type] of Object.entries(types)) {
2562
+ self[controlElementSymbol]
2563
+ .querySelector(`[${ATTRIBUTE_ROLE}="container"]`)
2564
+ .addEventListener(type, function (event) {
2565
+ const element = findTargetElementFromEvent(
2566
+ event,
2567
+ ATTRIBUTE_ROLE,
2568
+ "remove-badge",
2569
+ );
2570
+ if (element instanceof HTMLElement) {
2571
+ return;
2572
+ }
2573
+
2574
+ toggle.call(self);
2575
+ });
2576
+
2577
+ self[controlElementSymbol]
2578
+ .querySelector(`[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`)
2579
+ .addEventListener(type, function (event) {
2580
+ if (self.getOption("disabled", undefined) === true) {
2581
+ return;
2582
+ }
2583
+
2584
+ const path = event.composedPath();
2585
+ const element = path?.[0];
2586
+ if (element instanceof HTMLElement) {
2587
+ const control = element.closest(
2588
+ `[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`,
2589
+ );
2590
+ if (control instanceof HTMLElement) {
2591
+ if (control.classList.contains("clear")) {
2592
+ clearSelection.call(self);
2593
+
2594
+ fireCustomEvent(self, "monster-selection-cleared", {});
2595
+ } else {
2596
+ const element = findTargetElementFromEvent(
2597
+ event,
2598
+ ATTRIBUTE_ROLE,
2599
+ "remove-badge",
2600
+ );
2601
+ if (element instanceof HTMLElement) {
2602
+ return;
2603
+ }
2604
+
2605
+ toggle.call(self);
2606
+ }
2607
+ }
2608
+ }
2609
+ });
2610
+
2611
+ // badge, selection
2612
+ self.addEventListener(type, self[clearOptionEventHandler]);
2613
+ }
2614
+
2615
+ self.addEventListener("monster-change", self[changeEventHandler]);
2616
+ self.addEventListener("input", self[inputEventHandler]);
2617
+ self.addEventListener("keydown", self[keyEventHandler]);
2618
+
2619
+ return self;
2642
2620
  }
2643
2621
 
2644
2622
  /**
@@ -2646,70 +2624,70 @@ function initEventHandler() {
2646
2624
  * @return {Select}
2647
2625
  */
2648
2626
  function setStatusOrRemoveBadges(suggestion) {
2649
- requestAnimationFrame(() => {
2650
- const selection = this.getOption("selection");
2651
-
2652
- const clearAllFlag =
2653
- isArray(selection) &&
2654
- selection.length > 0 &&
2655
- this.getOption("features.clearAll") === true;
2656
-
2657
- const current = this.getOption("classes.statusOrRemoveBadge");
2658
-
2659
- if (suggestion === "error") {
2660
- if (current !== "error") {
2661
- this.setOption("classes.statusOrRemoveBadge", "error");
2662
- }
2663
- return;
2664
- }
2665
-
2666
- if (this[isLoadingSymbol] === true) {
2667
- if (current !== "loading") {
2668
- this.setOption("classes.statusOrRemoveBadge", "loading");
2669
- }
2670
- return;
2671
- }
2672
-
2673
- if (suggestion === "loading") {
2674
- if (current !== "loading") {
2675
- this.setOption("classes.statusOrRemoveBadge", "loading");
2676
- }
2677
- return;
2678
- }
2679
-
2680
- if (clearAllFlag) {
2681
- if (current !== "clear") {
2682
- this.setOption("classes.statusOrRemoveBadge", "clear");
2683
- }
2684
- return;
2685
- }
2686
-
2687
- if (this[controlElementSymbol].classList.contains("open")) {
2688
- if (current !== "open") {
2689
- this.setOption("classes.statusOrRemoveBadge", "open");
2690
- }
2691
- return;
2692
- }
2693
-
2694
- const options = this.getOption("options");
2695
- if (
2696
- options === undefined ||
2697
- options === null ||
2698
- (isArray(options) && options.length === 0)
2699
- ) {
2700
- if (current !== "empty") {
2701
- this.setOption("classes.statusOrRemoveBadge", "empty");
2702
- }
2703
- return;
2704
- }
2705
-
2706
- if (suggestion) {
2707
- if (current !== suggestion) {
2708
- this.setOption("classes.statusOrRemoveBadge", suggestion);
2709
- }
2710
- return;
2711
- }
2712
- });
2627
+ requestAnimationFrame(() => {
2628
+ const selection = this.getOption("selection");
2629
+
2630
+ const clearAllFlag =
2631
+ isArray(selection) &&
2632
+ selection.length > 0 &&
2633
+ this.getOption("features.clearAll") === true;
2634
+
2635
+ const current = this.getOption("classes.statusOrRemoveBadge");
2636
+
2637
+ if (suggestion === "error") {
2638
+ if (current !== "error") {
2639
+ this.setOption("classes.statusOrRemoveBadge", "error");
2640
+ }
2641
+ return;
2642
+ }
2643
+
2644
+ if (this[isLoadingSymbol] === true) {
2645
+ if (current !== "loading") {
2646
+ this.setOption("classes.statusOrRemoveBadge", "loading");
2647
+ }
2648
+ return;
2649
+ }
2650
+
2651
+ if (suggestion === "loading") {
2652
+ if (current !== "loading") {
2653
+ this.setOption("classes.statusOrRemoveBadge", "loading");
2654
+ }
2655
+ return;
2656
+ }
2657
+
2658
+ if (clearAllFlag) {
2659
+ if (current !== "clear") {
2660
+ this.setOption("classes.statusOrRemoveBadge", "clear");
2661
+ }
2662
+ return;
2663
+ }
2664
+
2665
+ if (this[controlElementSymbol].classList.contains("open")) {
2666
+ if (current !== "open") {
2667
+ this.setOption("classes.statusOrRemoveBadge", "open");
2668
+ }
2669
+ return;
2670
+ }
2671
+
2672
+ const options = this.getOption("options");
2673
+ if (
2674
+ options === undefined ||
2675
+ options === null ||
2676
+ (isArray(options) && options.length === 0)
2677
+ ) {
2678
+ if (current !== "empty") {
2679
+ this.setOption("classes.statusOrRemoveBadge", "empty");
2680
+ }
2681
+ return;
2682
+ }
2683
+
2684
+ if (suggestion) {
2685
+ if (current !== suggestion) {
2686
+ this.setOption("classes.statusOrRemoveBadge", suggestion);
2687
+ }
2688
+ return;
2689
+ }
2690
+ });
2713
2691
  }
2714
2692
 
2715
2693
  /**
@@ -2718,68 +2696,68 @@ function setStatusOrRemoveBadges(suggestion) {
2718
2696
  * @throws {Error} no shadow-root is defined
2719
2697
  */
2720
2698
  function initControlReferences() {
2721
- if (!this.shadowRoot) {
2722
- throw new Error("no shadow-root is defined");
2723
- }
2724
-
2725
- this[controlElementSymbol] = this.shadowRoot.querySelector(
2726
- `[${ATTRIBUTE_ROLE}=control]`,
2727
- );
2728
- this[selectionElementSymbol] = this.shadowRoot.querySelector(
2729
- `[${ATTRIBUTE_ROLE}=selection]`,
2730
- );
2731
- this[containerElementSymbol] = this.shadowRoot.querySelector(
2732
- `[${ATTRIBUTE_ROLE}=container]`,
2733
- );
2734
- this[popperElementSymbol] = this.shadowRoot.querySelector(
2735
- `[${ATTRIBUTE_ROLE}=popper]`,
2736
- );
2737
- this[inlineFilterElementSymbol] = this.shadowRoot.querySelector(
2738
- `[${ATTRIBUTE_ROLE}=filter][name="inline-filter"]`,
2739
- );
2740
- this[popperFilterElementSymbol] = this.shadowRoot.querySelector(
2741
- `[${ATTRIBUTE_ROLE}=filter][name="popper-filter"]`,
2742
- );
2743
- this[popperFilterContainerElementSymbol] =
2744
- this[popperFilterElementSymbol].parentElement;
2745
- this[optionsElementSymbol] = this.shadowRoot.querySelector(
2746
- `[${ATTRIBUTE_ROLE}=options]`,
2747
- );
2748
- this[noOptionsAvailableElementSymbol] = this.shadowRoot.querySelector(
2749
- `[${ATTRIBUTE_ROLE}="no-options"]`,
2750
- );
2751
- this[statusOrRemoveBadgesElementSymbol] = this.shadowRoot.querySelector(
2752
- `[${ATTRIBUTE_ROLE}=status-or-remove-badges]`,
2753
- );
2699
+ if (!this.shadowRoot) {
2700
+ throw new Error("no shadow-root is defined");
2701
+ }
2702
+
2703
+ this[controlElementSymbol] = this.shadowRoot.querySelector(
2704
+ `[${ATTRIBUTE_ROLE}=control]`,
2705
+ );
2706
+ this[selectionElementSymbol] = this.shadowRoot.querySelector(
2707
+ `[${ATTRIBUTE_ROLE}=selection]`,
2708
+ );
2709
+ this[containerElementSymbol] = this.shadowRoot.querySelector(
2710
+ `[${ATTRIBUTE_ROLE}=container]`,
2711
+ );
2712
+ this[popperElementSymbol] = this.shadowRoot.querySelector(
2713
+ `[${ATTRIBUTE_ROLE}=popper]`,
2714
+ );
2715
+ this[inlineFilterElementSymbol] = this.shadowRoot.querySelector(
2716
+ `[${ATTRIBUTE_ROLE}=filter][name="inline-filter"]`,
2717
+ );
2718
+ this[popperFilterElementSymbol] = this.shadowRoot.querySelector(
2719
+ `[${ATTRIBUTE_ROLE}=filter][name="popper-filter"]`,
2720
+ );
2721
+ this[popperFilterContainerElementSymbol] =
2722
+ this[popperFilterElementSymbol].parentElement;
2723
+ this[optionsElementSymbol] = this.shadowRoot.querySelector(
2724
+ `[${ATTRIBUTE_ROLE}=options]`,
2725
+ );
2726
+ this[noOptionsAvailableElementSymbol] = this.shadowRoot.querySelector(
2727
+ `[${ATTRIBUTE_ROLE}="no-options"]`,
2728
+ );
2729
+ this[statusOrRemoveBadgesElementSymbol] = this.shadowRoot.querySelector(
2730
+ `[${ATTRIBUTE_ROLE}=status-or-remove-badges]`,
2731
+ );
2754
2732
  }
2755
2733
 
2756
2734
  /**
2757
2735
  * @private
2758
2736
  */
2759
2737
  function updatePopper() {
2760
- if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) {
2761
- return;
2762
- }
2763
-
2764
- if (this.getOption("disabled", false) === true) {
2765
- return;
2766
- }
2767
-
2768
- new Processing(() => {
2769
- calcAndSetOptionsDimension.call(this);
2770
- positionPopper.call(
2771
- this,
2772
- this[controlElementSymbol],
2773
- this[popperElementSymbol],
2774
- this.getOption("popper", {}),
2775
- );
2776
- })
2777
- .run()
2778
- .catch((e) => {
2779
- addErrorAttribute(this, e);
2780
- });
2781
-
2782
- return this;
2738
+ if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) {
2739
+ return;
2740
+ }
2741
+
2742
+ if (this.getOption("disabled", false) === true) {
2743
+ return;
2744
+ }
2745
+
2746
+ new Processing(() => {
2747
+ calcAndSetOptionsDimension.call(this);
2748
+ positionPopper.call(
2749
+ this,
2750
+ this[controlElementSymbol],
2751
+ this[popperElementSymbol],
2752
+ this.getOption("popper", {}),
2753
+ );
2754
+ })
2755
+ .run()
2756
+ .catch((e) => {
2757
+ addErrorAttribute(this, e);
2758
+ });
2759
+
2760
+ return this;
2783
2761
  }
2784
2762
 
2785
2763
  /**
@@ -2787,8 +2765,8 @@ function updatePopper() {
2787
2765
  * @return {string}
2788
2766
  */
2789
2767
  function getTemplate() {
2790
- // language=HTML
2791
- return `
2768
+ // language=HTML
2769
+ return `
2792
2770
  <template id="options">
2793
2771
  <div data-monster-role="option" tabindex="-1"
2794
2772
  data-monster-attributes="