@schukai/monster 3.57.0 → 3.58.1

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.
@@ -4,61 +4,62 @@
4
4
  * This file is licensed under the AGPLv3 License.
5
5
  * License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
6
6
  */
7
- import {instanceSymbol} from "../../constants.mjs";
8
- import {internalSymbol} from "../../constants.mjs";
9
- import {buildMap} from "../../data/buildmap.mjs";
10
- import {DeadMansSwitch} from "../../util/deadmansswitch.mjs";
11
- import {positionPopper} from "./util/floating-ui.mjs";
7
+ import { instanceSymbol } from "../../constants.mjs";
8
+ import { internalSymbol } from "../../constants.mjs";
9
+ import { buildMap } from "../../data/buildmap.mjs";
10
+ import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
11
+ import { positionPopper } from "./util/floating-ui.mjs";
12
12
  import {
13
- addAttributeToken,
14
- findClosestByAttribute,
15
- removeAttributeToken,
13
+ addAttributeToken,
14
+ findClosestByAttribute,
15
+ removeAttributeToken,
16
16
  } from "../../dom/attributes.mjs";
17
17
  import {
18
- ATTRIBUTE_ERRORMESSAGE,
19
- ATTRIBUTE_PREFIX,
20
- ATTRIBUTE_ROLE,
18
+ ATTRIBUTE_ERRORMESSAGE,
19
+ ATTRIBUTE_PREFIX,
20
+ ATTRIBUTE_ROLE,
21
21
  } from "../../dom/constants.mjs";
22
- import {CustomControl} from "../../dom/customcontrol.mjs";
22
+ import { CustomControl } from "../../dom/customcontrol.mjs";
23
23
  import {
24
- assembleMethodSymbol,
25
- getSlottedElements,
26
- registerCustomElement, updaterTransformerMethodsSymbol,
24
+ assembleMethodSymbol,
25
+ getSlottedElements,
26
+ registerCustomElement,
27
+ updaterTransformerMethodsSymbol,
27
28
  } from "../../dom/customelement.mjs";
28
29
  import {
29
- findTargetElementFromEvent,
30
- fireCustomEvent,
31
- fireEvent,
30
+ findTargetElementFromEvent,
31
+ fireCustomEvent,
32
+ fireEvent,
32
33
  } from "../../dom/events.mjs";
33
- import {getDocument} from "../../dom/util.mjs";
34
- import {Formatter} from "../../text/formatter.mjs";
35
- import {getGlobal} from "../../types/global.mjs";
36
- import {ID} from "../../types/id.mjs";
34
+ import { getDocument } from "../../dom/util.mjs";
35
+ import { Formatter } from "../../text/formatter.mjs";
36
+ import { getGlobal } from "../../types/global.mjs";
37
+ import { ID } from "../../types/id.mjs";
37
38
  import {
38
- isArray,
39
- isFunction,
40
- isInteger,
41
- isIterable,
42
- isObject,
43
- isPrimitive,
44
- isString,
39
+ isArray,
40
+ isFunction,
41
+ isInteger,
42
+ isIterable,
43
+ isObject,
44
+ isPrimitive,
45
+ isString,
45
46
  } from "../../types/is.mjs";
46
- import {Observer} from "../../types/observer.mjs";
47
- import {ProxyObserver} from "../../types/proxyobserver.mjs";
48
- import {validateArray, validateString} from "../../types/validate.mjs";
49
- import {Processing} from "../../util/processing.mjs";
50
- import {STYLE_DISPLAY_MODE_BLOCK} from "./constants.mjs";
51
- import {SelectStyleSheet} from "./stylesheet/select.mjs";
47
+ import { Observer } from "../../types/observer.mjs";
48
+ import { ProxyObserver } from "../../types/proxyobserver.mjs";
49
+ import { validateArray, validateString } from "../../types/validate.mjs";
50
+ import { Processing } from "../../util/processing.mjs";
51
+ import { STYLE_DISPLAY_MODE_BLOCK } from "./constants.mjs";
52
+ import { SelectStyleSheet } from "./stylesheet/select.mjs";
52
53
  import {
53
- getDocumentTranslations,
54
- Translations,
54
+ getDocumentTranslations,
55
+ Translations,
55
56
  } from "../../i18n/translations.mjs";
56
57
 
57
58
  export {
58
- Select,
59
- popperElementSymbol,
60
- getSummaryTemplate,
61
- getSelectionTemplate,
59
+ Select,
60
+ popperElementSymbol,
61
+ getSummaryTemplate,
62
+ getSelectionTemplate,
62
63
  };
63
64
 
64
65
  /**
@@ -178,7 +179,7 @@ const popperFilterElementSymbol = Symbol("popperFilterElement");
178
179
  * @type {symbol}
179
180
  */
180
181
  const popperFilterContainerElementSymbol = Symbol(
181
- "popperFilterContainerElement",
182
+ "popperFilterContainerElement",
182
183
  );
183
184
 
184
185
  /**
@@ -314,482 +315,488 @@ const FILTER_POSITION_INLINE = "inline";
314
315
  * @fires Monster.Components.Form.event:monster-changed
315
316
  */
316
317
  class Select extends CustomControl {
317
- /**
318
- * @extends CustomControl
319
- */
320
- constructor() {
321
- super();
322
- initOptionObserver.call(this);
323
- }
324
-
325
- /**
326
- * This method is called by the `instanceof` operator.
327
- * @returns {symbol}
328
- * @since 2.1.0
329
- */
330
- static get [instanceSymbol]() {
331
- return Symbol.for("@schukai/monster/components/form/select@@instance");
332
- }
333
-
334
- /**
335
- * The current selection of the Select
336
- *
337
- * ```
338
- * e = document.querySelector('monster-select');
339
- * console.log(e.value)
340
- * // ↦ 1
341
- * // ↦ ['1','2']
342
- * ```
343
- *
344
- * @property {string|array}
345
- */
346
- get value() {
347
- return convertSelectionToValue.call(this, this.getOption("selection"));
348
- }
349
-
350
- /**
351
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals}
352
- * @return {boolean}
353
- */
354
- static get formAssociated() {
355
- return true;
356
- }
357
-
358
- /**
359
- * Set selection
360
- *
361
- * ```
362
- * e = document.querySelector('monster-select');
363
- * e.value=1
364
- * ```
365
- *
366
- * @property {string|array} value
367
- * @since 1.2.0
368
- * @throws {Error} unsupported type
369
- */
370
- set value(value) {
371
- const result = convertValueToSelection.call(this, value);
372
- setSelection
373
- .call(this, result.selection)
374
- .then(() => {
375
- })
376
- .catch((e) => {
377
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
378
- });
379
-
380
- }
381
-
382
- /**
383
- * To set the options via the html tag the attribute `data-monster-options` must be used.
384
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
385
- *
386
- * The individual configuration values can be found in the table.
387
- *
388
- * @property {Object} toggleEventType=click,touch List of event types to be observed for opening the dropdown
389
- * @property {boolean} delegatesFocus=false lorem [see mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/delegatesFocus)
390
- * @property {Object[]} options Selection of key identifier pairs available for selection and displayed in the dropdown.
391
- * @property {string} options[].label Label
392
- * @property {string} options[].value Value
393
- * @property {string} options[].visibility hidden or visible
394
- * @property {Array} selection Selected options
395
- * @property {Integer} showMaxOptions=10 Maximum number of visible options before a scroll bar should be displayed.
396
- * @property {string} type=radio Multiple (checkbox) or single selection (radio)
397
- * @property {string} name=(random id) Name of the form field
398
- * @property {string} url Load options from server per url
399
- * @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
400
- * @property {String} fetch.redirect=error
401
- * @property {String} fetch.method=GET
402
- * @property {String} fetch.mode=same-origin
403
- * @property {String} fetch.credentials=same-origin
404
- * @property {Object} fetch.headers={"accept":"application/json"}}
405
- * @property {Object} labels
406
- * @property {string} labels.cannot-be-loaded cannot be loaded
407
- * @property {string} labels.no-options-available no options available
408
- * @property {string} labels.select-an-option select an option
409
- * @property {string} labels.no-option no option in the list, maybe you have to change the filter
410
- * @property {Object} features List with features
411
- * @property {Boolean} features.clearAll=true Display of a delete button to delete the entire selection
412
- * @property {Boolean} features.clear=true Display of a delete key for deleting the specific selection
413
- * @property {Boolean} features.lazyLoad=false Load options when first opening the dropdown
414
- * @property {Boolean} features.closeOnSelect=false Close the dropdown when an option is selected (since 3.54.0)
415
- * @property {Boolean} filter.defaultValue=* Default filter value, if the filter is empty
416
- * @property {Boolean} filter.mode=options Filter mode, values: options, remote, disabled
417
- * @property {Object} templates Template definitions
418
- * @property {string} templates.main Main template
419
- * @property {string} templateMapping Mapping of the template placeholders
420
- * @property {string} templateMapping.selected Selected Template
421
- * @property {Object} popper [PopperJS Options](https://popper.js.org/docs/v2/)
422
- * @property {string} popper.placement=bottom PopperJS placement
423
- * @property {Object[]} modifiers={name:offset} PopperJS placement
424
- * @property {Object} mapping
425
- * @property {String} mapping.selector=* Path to select the appropriate entries
426
- * @property {String} mapping.labelTemplate="" template with the label placeholders in the form ${name}, where name is the key (**)
427
- * @property {String} mapping.valueTemplate="" template with the value placeholders in the form ${name}, where name is the key
428
- * @property {Monster.Components.Form~exampleFilterCallback|undefined} mapping.filter Filtering of values via a function
429
- * @property {Object} formatter
430
- * @property {Monster.Components.Form~formatterSelectionCallback|undefined} formatter.selection format selection label
431
- */
432
- get defaults() {
433
- return Object.assign(
434
- {},
435
- super.defaults,
436
- {
437
- toggleEventType: ["click", "touch"],
438
- delegatesFocus: false,
439
- options: [],
440
- selection: [],
441
- showMaxOptions: 10,
442
- type: "radio",
443
- name: new ID("s").toString(),
444
- features: {
445
- clearAll: true,
446
- clear: true,
447
- lazyLoad: false,
448
- closeOnSelect: false,
449
- },
450
- url: null,
451
- labels: {
452
- "cannot-be-loaded": "Cannot be loaded",
453
- "no-options-available": noOptionsAvailableMessage,
454
- "click-to-load-options": clickToLoadOptionsMessage,
455
- "select-an-option": "Select an option",
456
- "summary-text": {
457
- zero: "No entries were selected",
458
- one: '<span class="monster-badge-primary-pill">1</span> entry was selected',
459
- other:
460
- '<span class="monster-badge-primary-pill">${count}</span> entries were selected',
461
- },
462
- "no-options":
463
- "Unfortunately, there are no options available in the list.",
464
- "no-options-found":
465
- "No options are available in the list. Please consider modifying the filter.",
466
- },
467
- messages: {
468
- control: null,
469
- selected: null,
470
- emptyOptions: null,
471
- },
472
- fetch: {
473
- redirect: "error",
474
- method: "GET",
475
- mode: "same-origin",
476
- credentials: "same-origin",
477
- headers: {
478
- accept: "application/json",
479
- },
480
- },
481
- filter: {
482
- defaultValue: "*",
483
- mode: FILTER_MODE_DISABLED,
484
- position: FILTER_POSITION_INLINE,
485
- },
486
- classes: {
487
- badge: "monster-badge-primary",
488
- statusOrRemoveBadge: "empty",
489
- },
490
- mapping: {
491
- selector: "*",
492
- labelTemplate: "",
493
- valueTemplate: "",
494
- filter: null,
495
- },
496
- formatter: {
497
- selection: buildSelectionLabel,
498
- },
499
- templates: {
500
- main: getTemplate(),
501
- },
502
- templateMapping: {
503
- /** with the attribute `data-monster-selected-template` the template for the selected options can be defined. */
504
- selected: getSelectionTemplate(),
505
- },
506
-
507
- popper: {
508
- placement: "bottom",
509
- middleware: ["flip", "offset:1"],
510
- },
511
- },
512
- initOptionsFromArguments.call(this),
513
- );
514
- }
515
-
516
- /**
517
- * @return {Monster.Components.Form.Select}
518
- */
519
- [assembleMethodSymbol]() {
520
- const self = this;
521
- super[assembleMethodSymbol]();
522
-
523
- initControlReferences.call(self);
524
- initEventHandler.call(self);
525
-
526
- const lazyLoadFlag = self.getOption("features.lazyLoad");
527
-
528
- if (self.getOption("url") !== null && !lazyLoadFlag) {
529
- setStatusOrRemoveBadges.call(this, "loading");
530
-
531
- new Processing(200, () => {
532
- this.fetch()
533
- .then(() => {
534
- setTimeout(() => {
535
- let result;
536
- if (self.hasAttribute("value")) {
537
- result = setSelection.call(self, self.getAttribute("value"));
538
- } else {
539
- result = setSelection.call(self, []);
540
- }
541
-
542
- result
543
- .then(() => {
544
- })
545
- .catch((e) => {
546
- addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`);
547
- });
548
- }, 100);
549
- })
550
- .catch((e) => {
551
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
552
- setStatusOrRemoveBadges.call(this, "error");
553
- });
554
- })
555
- .run()
556
- .catch((e) => {
557
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
558
- });
559
- }
560
-
561
- let lastValue = self.value;
562
- self[internalSymbol].attachObserver(
563
-
564
- new Observer(function () {
565
-
566
- if (isObject(this) && this instanceof ProxyObserver) {
567
- const n = this.getSubject()?.options?.value;
568
-
569
- if (lastValue !== n) {
570
- lastValue = n;
571
- setSelection
572
- .call(self, n)
573
- .then(() => {
574
- })
575
- .catch((e) => {
576
- addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`);
577
- });
578
- }
579
- }
580
- }),
581
- );
582
-
583
- areOptionsAvailableAndInit.call(self);
584
-
585
- return this;
586
- }
587
-
588
- /**
589
- * The Button.click() method simulates a click on the internal button element.
590
- *
591
- * @since 3.27.0
592
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click}
593
- */
594
- click() {
595
- if (this.getOption("disabled") === true) {
596
- return;
597
- }
598
-
599
- toggle.call(this);
600
- }
601
-
602
- /**
603
- * The Button.focus() method sets focus on the internal button element.
604
- *
605
- * @since 3.27.0
606
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus}
607
- */
608
- focus(options) {
609
- if (this.getOption("disabled") === true) {
610
- return;
611
- }
612
-
613
- new Processing(() => {
614
- gatherState.call(this);
615
- focusFilter.call(this, options);
616
- })
617
- .run()
618
- .catch((e) => {
619
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
620
- });
621
- }
622
-
623
- /**
624
- * The Button.blur() method removes focus from the internal button element.
625
- * @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/blur
626
- */
627
- blur() {
628
- new Processing(() => {
629
- gatherState.call(this);
630
- blurFilter.call(this);
631
- })
632
- .run()
633
- .catch((e) => {
634
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
635
- });
636
- }
637
-
638
- /**
639
- * If no url is specified, the options are taken from the Component itself.
640
- *
641
- * @param {string|URL} url URL to fetch the options
642
- * @return {Promise}
643
- */
644
- fetch(url) {
645
- if (url instanceof URL) {
646
- url = url.toString();
647
- }
648
-
649
- if (url !== undefined && url !== null) {
650
- url = validateString(url);
651
- }
652
-
653
- return new Promise((resolve, reject) => {
654
- const response = fetchData.call(this, url).then((map) => {
655
- if (
656
- isObject(map) ||
657
- isArray(map) ||
658
- map instanceof Set ||
659
- map instanceof Map
660
- ) {
661
- this.importOptions(map);
662
- setTimeout(() => {
663
- resolve();
664
- }, 10);
665
- return;
666
- }
667
-
668
- reject(new Error("invalid response"));
669
- });
670
- });
671
- }
672
-
673
- /**
674
- * @return {void}
675
- */
676
- connectedCallback() {
677
- super.connectedCallback();
678
- const document = getDocument();
679
-
680
- for (const [, type] of Object.entries(["click", "touch"])) {
681
- // close on outside ui-events
682
- document.addEventListener(type, this[closeEventHandler]);
683
- }
684
-
685
- parseSlotsToOptions.call(this);
686
- attachResizeObserver.call(this);
687
- updatePopper.call(this);
688
-
689
- new Processing(() => {
690
- gatherState.call(this);
691
- focusFilter.call(this);
692
- }).run();
693
- }
694
-
695
- /**
696
- * @return {void}
697
- */
698
- disconnectedCallback() {
699
- super.disconnectedCallback();
700
- const document = getDocument();
701
-
702
- // close on outside ui-events
703
- for (const [, type] of Object.entries(["click", "touch"])) {
704
- document.removeEventListener(type, this[closeEventHandler]);
705
- }
706
-
707
- disconnectResizeObserver.call(this);
708
- }
709
-
710
- /**
711
- * Import Select Options from dataset
712
- * Not to be confused with the control defaults/options
713
- *
714
- * @since 0.16.0
715
- * @param {array|object|Map|Set} data
716
- * @return {Select}
717
- * @throws {Error} map is not iterable
718
- * @throws {Error} missing label configuration
719
- */
720
- importOptions(data) {
721
- const mappingOptions = this.getOption("mapping", {});
722
- const selector = mappingOptions?.["selector"];
723
- const labelTemplate = mappingOptions?.["labelTemplate"];
724
- const valueTemplate = mappingOptions?.["valueTemplate"];
725
- const filter = mappingOptions?.["filter"];
726
-
727
- let flag = false;
728
- if (labelTemplate === "") {
729
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty label template");
730
- flag = true;
731
- }
732
-
733
- if (valueTemplate === "") {
734
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty value template");
735
- flag = true;
736
- }
737
-
738
- if (flag === true) {
739
- throw new Error("missing label configuration");
740
- }
741
-
742
- const map = buildMap(data, selector, labelTemplate, valueTemplate, filter);
743
-
744
- const options = [];
745
- if (!isIterable(map)) {
746
- throw new Error("map is not iterable");
747
- }
748
-
749
- const visibility = "visible";
750
-
751
- map.forEach((label, value) => {
752
- options.push({
753
- value,
754
- label,
755
- visibility,
756
- });
757
- });
758
-
759
- runAsOptionLengthChanged.call(this, map.size);
760
- this.setOption("options", options);
761
-
762
- fireCustomEvent(this, "monster-options-set", {
763
- options,
764
- });
765
-
766
- return this;
767
- }
768
-
769
- /**
770
- * @private
771
- * @return {Monster.Components.Form.Select}
772
- */
773
- calcAndSetOptionsDimension() {
774
- calcAndSetOptionsDimension.call(this);
775
- return this;
776
- }
777
-
778
- /**
779
- *
780
- * @return {string}
781
- */
782
- static getTag() {
783
- return "monster-select";
784
- }
785
-
786
- /**
787
- *
788
- * @return {CSSStyleSheet[]}
789
- */
790
- static getCSSStyleSheet() {
791
- return [SelectStyleSheet];
792
- }
318
+ /**
319
+ * @extends CustomControl
320
+ */
321
+ constructor() {
322
+ super();
323
+ initOptionObserver.call(this);
324
+ }
325
+
326
+ /**
327
+ * This method is called by the `instanceof` operator.
328
+ * @returns {symbol}
329
+ * @since 2.1.0
330
+ */
331
+ static get [instanceSymbol]() {
332
+ return Symbol.for("@schukai/monster/components/form/select@@instance");
333
+ }
334
+
335
+ /**
336
+ * The current selection of the Select
337
+ *
338
+ * ```
339
+ * e = document.querySelector('monster-select');
340
+ * console.log(e.value)
341
+ * // ↦ 1
342
+ * // ↦ ['1','2']
343
+ * ```
344
+ *
345
+ * @property {string|array}
346
+ */
347
+ get value() {
348
+ return convertSelectionToValue.call(this, this.getOption("selection"));
349
+ }
350
+
351
+ /**
352
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals}
353
+ * @return {boolean}
354
+ */
355
+ static get formAssociated() {
356
+ return true;
357
+ }
358
+
359
+ /**
360
+ * Set selection
361
+ *
362
+ * ```
363
+ * e = document.querySelector('monster-select');
364
+ * e.value=1
365
+ * ```
366
+ *
367
+ * @property {string|array} value
368
+ * @since 1.2.0
369
+ * @throws {Error} unsupported type
370
+ */
371
+ set value(value) {
372
+ const result = convertValueToSelection.call(this, value);
373
+ setSelection
374
+ .call(this, result.selection)
375
+ .then(() => {})
376
+ .catch((e) => {
377
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
378
+ });
379
+ }
380
+
381
+ /**
382
+ * To set the options via the html tag the attribute `data-monster-options` must be used.
383
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
384
+ *
385
+ * The individual configuration values can be found in the table.
386
+ *
387
+ * @property {Object} toggleEventType=click,touch List of event types to be observed for opening the dropdown
388
+ * @property {boolean} delegatesFocus=false lorem [see mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/delegatesFocus)
389
+ * @property {Object[]} options Selection of key identifier pairs available for selection and displayed in the dropdown.
390
+ * @property {string} options[].label
391
+ * @property {string} options[].value
392
+ * @property {string} options[].visibility hidden or visible
393
+ * @property {Array} selection Selected options
394
+ * @property {Integer} showMaxOptions=10 Maximum number of visible options before a scroll bar should be displayed.
395
+ * @property {string} type=radio Multiple (checkbox) or single selection (radio)
396
+ * @property {string} name=(random id) Name of the form field
397
+ * @property {string} url Load options from server per url
398
+ * @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
399
+ * @property {String} fetch.redirect=error
400
+ * @property {String} fetch.method=GET
401
+ * @property {String} fetch.mode=same-origin
402
+ * @property {String} fetch.credentials=same-origin
403
+ * @property {Object} fetch.headers={"accept":"application/json"}}
404
+ * @property {Object} labels
405
+ * @property {string} labels.cannot-be-loaded cannot be loaded
406
+ * @property {string} labels.no-options-available no options available
407
+ * @property {string} labels.select-an-option select an option
408
+ * @property {string} labels.no-option no option in the list, maybe you have to change the filter
409
+ * @property {Object} features List with features
410
+ * @property {Boolean} features.clearAll=true Display of a delete button to delete the entire selection
411
+ * @property {Boolean} features.clear=true Display of a delete key for deleting the specific selection
412
+ * @property {Boolean} features.lazyLoad=false Load options when first opening the dropdown
413
+ * @property {Boolean} features.closeOnSelect=false Close the dropdown when an option is selected (since 3.54.0)
414
+ * @property {Boolean} features.emptyValueIfNoOptions=false If no options are available, the selection is set to an empty array
415
+ * @property {Boolean} filter.defaultValue=* Default filter value, if the filter is empty
416
+ * @property {Boolean} filter.mode=options Filter mode, values: options, remote, disabled
417
+ * @property {Object} templates Template definitions
418
+ * @property {string} templates.main Main template
419
+ * @property {string} templateMapping Mapping of the template placeholders
420
+ * @property {string} templateMapping.selected Selected Template
421
+ * @property {Object} popper [PopperJS Options](https://popper.js.org/docs/v2/)
422
+ * @property {string} popper.placement=bottom PopperJS placement
423
+ * @property {Object[]} modifiers={name:offset} PopperJS placement
424
+ * @property {Object} mapping
425
+ * @property {String} mapping.selector=* Path to select the appropriate entries
426
+ * @property {String} mapping.labelTemplate="" template with the label placeholders in the form ${name}, where name is the key (**)
427
+ * @property {String} mapping.valueTemplate="" template with the value placeholders in the form ${name}, where name is the key
428
+ * @property {Monster.Components.Form~exampleFilterCallback|undefined} mapping.filter Filtering of values via a function
429
+ * @property {Object} formatter
430
+ * @property {Monster.Components.Form~formatterSelectionCallback|undefined} formatter.selection format selection label
431
+ */
432
+ get defaults() {
433
+ return Object.assign(
434
+ {},
435
+ super.defaults,
436
+ {
437
+ toggleEventType: ["click", "touch"],
438
+ delegatesFocus: false,
439
+ options: [],
440
+ selection: [],
441
+ showMaxOptions: 10,
442
+ type: "radio",
443
+ name: new ID("s").toString(),
444
+ features: {
445
+ clearAll: true,
446
+ clear: true,
447
+ lazyLoad: false,
448
+ closeOnSelect: false,
449
+ emptyValueIfNoOptions: false,
450
+ },
451
+ url: null,
452
+ labels: {
453
+ "cannot-be-loaded": "Cannot be loaded",
454
+ "no-options-available": noOptionsAvailableMessage,
455
+ "click-to-load-options": clickToLoadOptionsMessage,
456
+ "select-an-option": "Select an option",
457
+ "summary-text": {
458
+ zero: "No entries were selected",
459
+ one: '<span class="monster-badge-primary-pill">1</span> entry was selected',
460
+ other:
461
+ '<span class="monster-badge-primary-pill">${count}</span> entries were selected',
462
+ },
463
+ "no-options":
464
+ "Unfortunately, there are no options available in the list.",
465
+ "no-options-found":
466
+ "No options are available in the list. Please consider modifying the filter.",
467
+ },
468
+ messages: {
469
+ control: null,
470
+ selected: null,
471
+ emptyOptions: null,
472
+ },
473
+ fetch: {
474
+ redirect: "error",
475
+ method: "GET",
476
+ mode: "same-origin",
477
+ credentials: "same-origin",
478
+ headers: {
479
+ accept: "application/json",
480
+ },
481
+ },
482
+ filter: {
483
+ defaultValue: "*",
484
+ mode: FILTER_MODE_DISABLED,
485
+ position: FILTER_POSITION_INLINE,
486
+ },
487
+ classes: {
488
+ badge: "monster-badge-primary",
489
+ statusOrRemoveBadge: "empty",
490
+ },
491
+ mapping: {
492
+ selector: "*",
493
+ labelTemplate: "",
494
+ valueTemplate: "",
495
+ filter: null,
496
+ },
497
+ formatter: {
498
+ selection: buildSelectionLabel,
499
+ },
500
+ templates: {
501
+ main: getTemplate(),
502
+ },
503
+ templateMapping: {
504
+ /** with the attribute `data-monster-selected-template` the template for the selected options can be defined. */
505
+ selected: getSelectionTemplate(),
506
+ },
507
+
508
+ popper: {
509
+ placement: "bottom",
510
+ middleware: ["flip", "offset:1"],
511
+ },
512
+ },
513
+ initOptionsFromArguments.call(this),
514
+ );
515
+ }
516
+
517
+ /**
518
+ * @return {Monster.Components.Form.Select}
519
+ */
520
+ [assembleMethodSymbol]() {
521
+ const self = this;
522
+ super[assembleMethodSymbol]();
523
+
524
+ initControlReferences.call(self);
525
+ initEventHandler.call(self);
526
+
527
+ const lazyLoadFlag = self.getOption("features.lazyLoad");
528
+
529
+ if (self.hasAttribute("value")) {
530
+ new Processing(10, () => {
531
+ this.value = this.getAttribute("value");
532
+ })
533
+ .run()
534
+ .catch((e) => {
535
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
536
+ });
537
+ }
538
+
539
+ if (self.getOption("url") !== null && !lazyLoadFlag) {
540
+ setStatusOrRemoveBadges.call(this, "loading");
541
+
542
+ new Processing(200, () => {
543
+ this.fetch()
544
+ .then(() => {
545
+ setTimeout(() => {
546
+ let result;
547
+ if (self.hasAttribute("value")) {
548
+ result = setSelection.call(self, self.getAttribute("value"));
549
+ } else {
550
+ result = setSelection.call(self, []);
551
+ }
552
+
553
+ result
554
+ .then(() => {})
555
+ .catch((e) => {
556
+ addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`);
557
+ });
558
+ }, 100);
559
+ })
560
+ .catch((e) => {
561
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
562
+ setStatusOrRemoveBadges.call(this, "error");
563
+ });
564
+ })
565
+ .run()
566
+ .catch((e) => {
567
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
568
+ });
569
+ }
570
+
571
+ let lastValue = self.value;
572
+ self[internalSymbol].attachObserver(
573
+ new Observer(function () {
574
+ if (isObject(this) && this instanceof ProxyObserver) {
575
+ const n = this.getSubject()?.options?.value;
576
+
577
+ if (lastValue !== n) {
578
+ lastValue = n;
579
+ setSelection
580
+ .call(self, n)
581
+ .then(() => {})
582
+ .catch((e) => {
583
+ addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`);
584
+ });
585
+ }
586
+ }
587
+ }),
588
+ );
589
+
590
+ areOptionsAvailableAndInit.call(self);
591
+
592
+ return this;
593
+ }
594
+
595
+ /**
596
+ * The Button.click() method simulates a click on the internal button element.
597
+ *
598
+ * @since 3.27.0
599
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click}
600
+ */
601
+ click() {
602
+ if (this.getOption("disabled") === true) {
603
+ return;
604
+ }
605
+
606
+ toggle.call(this);
607
+ }
608
+
609
+ /**
610
+ * The Button.focus() method sets focus on the internal button element.
611
+ *
612
+ * @since 3.27.0
613
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus}
614
+ */
615
+ focus(options) {
616
+ if (this.getOption("disabled") === true) {
617
+ return;
618
+ }
619
+
620
+ new Processing(() => {
621
+ gatherState.call(this);
622
+ focusFilter.call(this, options);
623
+ })
624
+ .run()
625
+ .catch((e) => {
626
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
627
+ });
628
+ }
629
+
630
+ /**
631
+ * The Button.blur() method removes focus from the internal button element.
632
+ * @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/blur
633
+ */
634
+ blur() {
635
+ new Processing(() => {
636
+ gatherState.call(this);
637
+ blurFilter.call(this);
638
+ })
639
+ .run()
640
+ .catch((e) => {
641
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
642
+ });
643
+ }
644
+
645
+ /**
646
+ * If no url is specified, the options are taken from the Component itself.
647
+ *
648
+ * @param {string|URL} url URL to fetch the options
649
+ * @return {Promise}
650
+ */
651
+ fetch(url) {
652
+ if (url instanceof URL) {
653
+ url = url.toString();
654
+ }
655
+
656
+ if (url !== undefined && url !== null) {
657
+ url = validateString(url);
658
+ }
659
+
660
+ return new Promise((resolve, reject) => {
661
+ const response = fetchData.call(this, url).then((map) => {
662
+ if (
663
+ isObject(map) ||
664
+ isArray(map) ||
665
+ map instanceof Set ||
666
+ map instanceof Map
667
+ ) {
668
+ this.importOptions(map);
669
+ setTimeout(() => {
670
+ resolve();
671
+ }, 10);
672
+ return;
673
+ }
674
+
675
+ reject(new Error("invalid response"));
676
+ });
677
+ });
678
+ }
679
+
680
+ /**
681
+ * @return {void}
682
+ */
683
+ connectedCallback() {
684
+ super.connectedCallback();
685
+ const document = getDocument();
686
+
687
+ for (const [, type] of Object.entries(["click", "touch"])) {
688
+ // close on outside ui-events
689
+ document.addEventListener(type, this[closeEventHandler]);
690
+ }
691
+
692
+ parseSlotsToOptions.call(this);
693
+ attachResizeObserver.call(this);
694
+ updatePopper.call(this);
695
+
696
+ new Processing(() => {
697
+ gatherState.call(this);
698
+ focusFilter.call(this);
699
+ }).run();
700
+ }
701
+
702
+ /**
703
+ * @return {void}
704
+ */
705
+ disconnectedCallback() {
706
+ super.disconnectedCallback();
707
+ const document = getDocument();
708
+
709
+ // close on outside ui-events
710
+ for (const [, type] of Object.entries(["click", "touch"])) {
711
+ document.removeEventListener(type, this[closeEventHandler]);
712
+ }
713
+
714
+ disconnectResizeObserver.call(this);
715
+ }
716
+
717
+ /**
718
+ * Import Select Options from dataset
719
+ * Not to be confused with the control defaults/options
720
+ *
721
+ * @since 0.16.0
722
+ * @param {array|object|Map|Set} data
723
+ * @return {Select}
724
+ * @throws {Error} map is not iterable
725
+ * @throws {Error} missing label configuration
726
+ */
727
+ importOptions(data) {
728
+ const mappingOptions = this.getOption("mapping", {});
729
+ const selector = mappingOptions?.["selector"];
730
+ const labelTemplate = mappingOptions?.["labelTemplate"];
731
+ const valueTemplate = mappingOptions?.["valueTemplate"];
732
+ const filter = mappingOptions?.["filter"];
733
+
734
+ let flag = false;
735
+ if (labelTemplate === "") {
736
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty label template");
737
+ flag = true;
738
+ }
739
+
740
+ if (valueTemplate === "") {
741
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty value template");
742
+ flag = true;
743
+ }
744
+
745
+ if (flag === true) {
746
+ throw new Error("missing label configuration");
747
+ }
748
+
749
+ const map = buildMap(data, selector, labelTemplate, valueTemplate, filter);
750
+
751
+ const options = [];
752
+ if (!isIterable(map)) {
753
+ throw new Error("map is not iterable");
754
+ }
755
+
756
+ const visibility = "visible";
757
+
758
+ map.forEach((label, value) => {
759
+ options.push({
760
+ value,
761
+ label,
762
+ visibility,
763
+ });
764
+ });
765
+
766
+ runAsOptionLengthChanged.call(this, map.size);
767
+ this.setOption("options", options);
768
+
769
+ fireCustomEvent(this, "monster-options-set", {
770
+ options,
771
+ });
772
+
773
+ return this;
774
+ }
775
+
776
+ /**
777
+ * @private
778
+ * @return {Monster.Components.Form.Select}
779
+ */
780
+ calcAndSetOptionsDimension() {
781
+ calcAndSetOptionsDimension.call(this);
782
+ return this;
783
+ }
784
+
785
+ /**
786
+ *
787
+ * @return {string}
788
+ */
789
+ static getTag() {
790
+ return "monster-select";
791
+ }
792
+
793
+ /**
794
+ *
795
+ * @return {CSSStyleSheet[]}
796
+ */
797
+ static getCSSStyleSheet() {
798
+ return [SelectStyleSheet];
799
+ }
793
800
  }
794
801
 
795
802
  /**
@@ -804,64 +811,64 @@ class Select extends CustomControl {
804
811
  * @return {object}
805
812
  */
806
813
  function initOptionsFromArguments() {
807
- const options = {};
808
-
809
- const template = this.getAttribute("data-monster-selected-template");
810
- if (isString(template)) {
811
- if (!options["templateMapping"]) options["templateMapping"] = {};
812
-
813
- switch (template) {
814
- case "summary":
815
- case "default":
816
- options["templateMapping"]["selected"] = getSummaryTemplate();
817
- break;
818
- case "selected":
819
- options["templateMapping"]["selected"] = getSelectionTemplate();
820
- break;
821
- default:
822
- addAttributeToken(
823
- this,
824
- ATTRIBUTE_ERRORMESSAGE,
825
- "invalid template, use summary or selected",
826
- );
827
- }
828
- }
829
-
830
- return options;
814
+ const options = {};
815
+
816
+ const template = this.getAttribute("data-monster-selected-template");
817
+ if (isString(template)) {
818
+ if (!options["templateMapping"]) options["templateMapping"] = {};
819
+
820
+ switch (template) {
821
+ case "summary":
822
+ case "default":
823
+ options["templateMapping"]["selected"] = getSummaryTemplate();
824
+ break;
825
+ case "selected":
826
+ options["templateMapping"]["selected"] = getSelectionTemplate();
827
+ break;
828
+ default:
829
+ addAttributeToken(
830
+ this,
831
+ ATTRIBUTE_ERRORMESSAGE,
832
+ "invalid template, use summary or selected",
833
+ );
834
+ }
835
+ }
836
+
837
+ return options;
831
838
  }
832
839
 
833
840
  /**
834
841
  * @private
835
842
  */
836
843
  function attachResizeObserver() {
837
- // against flickering
838
- this[resizeObserverSymbol] = new ResizeObserver((entries) => {
839
- if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
840
- try {
841
- this[timerCallbackSymbol].touch();
842
- return;
843
- } catch (e) {
844
- delete this[timerCallbackSymbol];
845
- }
846
- }
847
-
848
- this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
849
- updatePopper.call(this);
850
- delete this[timerCallbackSymbol];
851
- });
852
- });
853
-
854
- this[resizeObserverSymbol].observe(this.parentElement);
844
+ // against flickering
845
+ this[resizeObserverSymbol] = new ResizeObserver((entries) => {
846
+ if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
847
+ try {
848
+ this[timerCallbackSymbol].touch();
849
+ return;
850
+ } catch (e) {
851
+ delete this[timerCallbackSymbol];
852
+ }
853
+ }
854
+
855
+ this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
856
+ updatePopper.call(this);
857
+ delete this[timerCallbackSymbol];
858
+ });
859
+ });
860
+
861
+ this[resizeObserverSymbol].observe(this.parentElement);
855
862
  }
856
863
 
857
864
  function disconnectResizeObserver() {
858
- if (this[resizeObserverSymbol] instanceof ResizeObserver) {
859
- this[resizeObserverSymbol].disconnect();
860
- }
865
+ if (this[resizeObserverSymbol] instanceof ResizeObserver) {
866
+ this[resizeObserverSymbol].disconnect();
867
+ }
861
868
  }
862
869
 
863
870
  function getSelectionTemplate() {
864
- return `<div data-monster-role="selection"
871
+ return `<div data-monster-role="selection"
865
872
  data-monster-insert="selection path:selection" role="search"
866
873
  ><input type="text" role="searchbox"
867
874
  part="inline-filter" name="inline-filter"
@@ -873,7 +880,7 @@ function getSelectionTemplate() {
873
880
  }
874
881
 
875
882
  function getSummaryTemplate() {
876
- return `<div data-monster-role="selection" role="search">
883
+ return `<div data-monster-role="selection" role="search">
877
884
  <input type="text" role="searchbox"
878
885
  part="inline-filter" name="inline-filter"
879
886
  data-monster-role="filter"
@@ -889,35 +896,35 @@ function getSummaryTemplate() {
889
896
  * @private
890
897
  */
891
898
  function parseSlotsToOptions() {
892
- let options = this.getOption("options");
893
- if (!isIterable(options)) {
894
- options = [];
895
- }
896
-
897
- let counter = 1;
898
- getSlottedElements.call(this, "div").forEach((node) => {
899
- let value = (counter++).toString();
900
- let visibility = "visible";
901
-
902
- if (node.hasAttribute("data-monster-value")) {
903
- value = node.getAttribute("data-monster-value");
904
- }
905
-
906
- if (node.style.display === "none") {
907
- visibility = "hidden";
908
- }
909
-
910
- const label = node.outerHTML;
911
-
912
- options.push({
913
- value,
914
- label,
915
- visibility,
916
- });
917
- });
918
-
919
- runAsOptionLengthChanged.call(this, options.length);
920
- this.setOption("options", options);
899
+ let options = this.getOption("options");
900
+ if (!isIterable(options)) {
901
+ options = [];
902
+ }
903
+
904
+ let counter = 1;
905
+ getSlottedElements.call(this, "div").forEach((node) => {
906
+ let value = (counter++).toString();
907
+ let visibility = "visible";
908
+
909
+ if (node.hasAttribute("data-monster-value")) {
910
+ value = node.getAttribute("data-monster-value");
911
+ }
912
+
913
+ if (node.style.display === "none") {
914
+ visibility = "hidden";
915
+ }
916
+
917
+ const label = node.outerHTML;
918
+
919
+ options.push({
920
+ value,
921
+ label,
922
+ visibility,
923
+ });
924
+ });
925
+
926
+ runAsOptionLengthChanged.call(this, options.length);
927
+ this.setOption("options", options);
921
928
  }
922
929
 
923
930
  /**
@@ -927,39 +934,39 @@ function parseSlotsToOptions() {
927
934
  * @param {int} targetLength
928
935
  */
929
936
  function runAsOptionLengthChanged(targetLength) {
930
- const self = this;
931
-
932
- if (!self[optionsElementSymbol]) {
933
- return;
934
- }
935
-
936
- const callback = function (mutationsList, observer) {
937
- const run = false;
938
- for (const mutation of mutationsList) {
939
- if (mutation.type === "childList") {
940
- const run = true;
941
- break;
942
- }
943
- }
944
-
945
- if (run === true) {
946
- const nodes = self[optionsElementSymbol].querySelectorAll(
947
- `div[${ATTRIBUTE_ROLE}=option]`,
948
- );
949
-
950
- if (nodes.length === targetLength) {
951
- checkOptionState.call(self);
952
- observer.disconnect();
953
- }
954
- }
955
- };
956
-
957
- const observer = new MutationObserver(callback);
958
- observer.observe(self[optionsElementSymbol], {
959
- attributes: false,
960
- childList: true,
961
- subtree: true,
962
- });
937
+ const self = this;
938
+
939
+ if (!self[optionsElementSymbol]) {
940
+ return;
941
+ }
942
+
943
+ const callback = function (mutationsList, observer) {
944
+ const run = false;
945
+ for (const mutation of mutationsList) {
946
+ if (mutation.type === "childList") {
947
+ const run = true;
948
+ break;
949
+ }
950
+ }
951
+
952
+ if (run === true) {
953
+ const nodes = self[optionsElementSymbol].querySelectorAll(
954
+ `div[${ATTRIBUTE_ROLE}=option]`,
955
+ );
956
+
957
+ if (nodes.length === targetLength) {
958
+ checkOptionState.call(self);
959
+ observer.disconnect();
960
+ }
961
+ }
962
+ };
963
+
964
+ const observer = new MutationObserver(callback);
965
+ observer.observe(self[optionsElementSymbol], {
966
+ attributes: false,
967
+ childList: true,
968
+ subtree: true,
969
+ });
963
970
  }
964
971
 
965
972
  /**
@@ -968,18 +975,18 @@ function runAsOptionLengthChanged(targetLength) {
968
975
  * @return {*}
969
976
  */
970
977
  function buildSelectionLabel(value) {
971
- const options = this.getOption("options");
972
-
973
- for (let i = 0; i < options.length; i++) {
974
- const o = options?.[i];
975
- if (isObject(o) && o?.["value"] === value) {
976
- return o?.["label"];
977
- } else if (isPrimitive(o) && o === value) {
978
- return o;
979
- }
980
- }
981
-
982
- return undefined;
978
+ const options = this.getOption("options");
979
+
980
+ for (let i = 0; i < options.length; i++) {
981
+ const o = options?.[i];
982
+ if (isObject(o) && o?.["value"] === value) {
983
+ return o?.["label"];
984
+ } else if (isPrimitive(o) && o === value) {
985
+ return o;
986
+ }
987
+ }
988
+
989
+ return undefined;
983
990
  }
984
991
 
985
992
  /**
@@ -989,17 +996,17 @@ function buildSelectionLabel(value) {
989
996
  * @throws {Error} no value found
990
997
  */
991
998
  function getSelectionLabel(value) {
992
- const callback = this.getOption("formatter.selection");
993
- if (isFunction(callback)) {
994
- const label = callback.call(this, value);
995
- if (isString(label)) return label;
996
- }
999
+ const callback = this.getOption("formatter.selection");
1000
+ if (isFunction(callback)) {
1001
+ const label = callback.call(this, value);
1002
+ if (isString(label)) return label;
1003
+ }
997
1004
 
998
- if (isString(value) || isInteger(value)) {
999
- return `${value}`;
1000
- }
1005
+ if (isString(value) || isInteger(value)) {
1006
+ return `${value}`;
1007
+ }
1001
1008
 
1002
- return this.getOption("labels.cannot-be-loaded", value);
1009
+ return this.getOption("labels.cannot-be-loaded", value);
1003
1010
  }
1004
1011
 
1005
1012
  /**
@@ -1007,25 +1014,25 @@ function getSelectionLabel(value) {
1007
1014
  * @param {Event} event
1008
1015
  */
1009
1016
  function handleToggleKeyboardEvents(event) {
1010
- switch (event?.["code"]) {
1011
- case "Escape":
1012
- toggle.call(this);
1013
- event.preventDefault();
1014
- break;
1015
- case "Space":
1016
- toggle.call(this);
1017
- event.preventDefault();
1018
- break;
1019
- case "ArrowDown":
1020
- show.call(this);
1021
- activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1022
- event.preventDefault();
1023
- break;
1024
- case "ArrowUp":
1025
- hide.call(this);
1026
- event.preventDefault();
1027
- break;
1028
- }
1017
+ switch (event?.["code"]) {
1018
+ case "Escape":
1019
+ toggle.call(this);
1020
+ event.preventDefault();
1021
+ break;
1022
+ case "Space":
1023
+ toggle.call(this);
1024
+ event.preventDefault();
1025
+ break;
1026
+ case "ArrowDown":
1027
+ show.call(this);
1028
+ activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1029
+ event.preventDefault();
1030
+ break;
1031
+ case "ArrowUp":
1032
+ hide.call(this);
1033
+ event.preventDefault();
1034
+ break;
1035
+ }
1029
1036
  }
1030
1037
 
1031
1038
  /**
@@ -1035,38 +1042,35 @@ function handleToggleKeyboardEvents(event) {
1035
1042
  * @this CustomElement
1036
1043
  */
1037
1044
  function initOptionObserver() {
1038
- const self = this;
1039
-
1040
- self.attachObserver(
1041
- new Observer(function () {
1042
- new Processing(() => {
1043
- try {
1044
- self.updateI18n();
1045
- } catch (e) {
1046
- }
1047
- try {
1048
- areOptionsAvailableAndInit.call(self);
1049
- } catch (e) {
1050
- }
1051
-
1052
- setSummaryAndControlText.call(self);
1053
- }).run();
1054
- }),
1055
- );
1045
+ const self = this;
1046
+
1047
+ self.attachObserver(
1048
+ new Observer(function () {
1049
+ new Processing(() => {
1050
+ try {
1051
+ self.updateI18n();
1052
+ } catch (e) {}
1053
+ try {
1054
+ areOptionsAvailableAndInit.call(self);
1055
+ } catch (e) {}
1056
+
1057
+ setSummaryAndControlText.call(self);
1058
+ }).run();
1059
+ }),
1060
+ );
1056
1061
  }
1057
1062
 
1058
1063
  function getDefaultTranslation() {
1059
- const translation = new Translations("en").assignTranslations(
1060
- this.getOption("labels", {}),
1061
- );
1064
+ const translation = new Translations("en").assignTranslations(
1065
+ this.getOption("labels", {}),
1066
+ );
1062
1067
 
1063
- try {
1064
- const doc = getDocumentTranslations();
1065
- translation.locale = doc.locale;
1066
- } catch (e) {
1067
- }
1068
+ try {
1069
+ const doc = getDocumentTranslations();
1070
+ translation.locale = doc.locale;
1071
+ } catch (e) {}
1068
1072
 
1069
- return translation;
1073
+ return translation;
1070
1074
  }
1071
1075
 
1072
1076
  /**
@@ -1074,36 +1078,36 @@ function getDefaultTranslation() {
1074
1078
  * @returns {string|*}
1075
1079
  */
1076
1080
  function setSummaryAndControlText() {
1077
- const translations = getDefaultTranslation.call(this);
1078
- const selections = this.getOption("selection");
1079
-
1080
- const text = translations.getPluralRuleText(
1081
- "summary-text",
1082
- selections.length,
1083
- "",
1084
- );
1085
-
1086
- const selectedText = new Formatter({
1087
- count: String(selections.length),
1088
- }).format(text);
1089
-
1090
- this.setOption("messages.selected", selectedText);
1091
-
1092
- const current = this.getOption("messages.control");
1093
- const msg = this.getOption("labels.select-an-option");
1094
-
1095
- if (
1096
- current === "" ||
1097
- current === undefined ||
1098
- current === msg ||
1099
- current === null
1100
- ) {
1101
- if (selections === undefined || selections.length === 0) {
1102
- this.setOption("messages.control", msg);
1103
- } else {
1104
- this.setOption("messages.control", "");
1105
- }
1106
- }
1081
+ const translations = getDefaultTranslation.call(this);
1082
+ const selections = this.getOption("selection");
1083
+
1084
+ const text = translations.getPluralRuleText(
1085
+ "summary-text",
1086
+ selections.length,
1087
+ "",
1088
+ );
1089
+
1090
+ const selectedText = new Formatter({
1091
+ count: String(selections.length),
1092
+ }).format(text);
1093
+
1094
+ this.setOption("messages.selected", selectedText);
1095
+
1096
+ const current = this.getOption("messages.control");
1097
+ const msg = this.getOption("labels.select-an-option");
1098
+
1099
+ if (
1100
+ current === "" ||
1101
+ current === undefined ||
1102
+ current === msg ||
1103
+ current === null
1104
+ ) {
1105
+ if (selections === undefined || selections.length === 0) {
1106
+ this.setOption("messages.control", msg);
1107
+ } else {
1108
+ this.setOption("messages.control", "");
1109
+ }
1110
+ }
1107
1111
  }
1108
1112
 
1109
1113
  /**
@@ -1111,9 +1115,9 @@ function setSummaryAndControlText() {
1111
1115
  * @return {NodeList}
1112
1116
  */
1113
1117
  function getOptionElements() {
1114
- return this[optionsElementSymbol].querySelectorAll(
1115
- `[${ATTRIBUTE_ROLE}=option]`,
1116
- );
1118
+ return this[optionsElementSymbol].querySelectorAll(
1119
+ `[${ATTRIBUTE_ROLE}=option]`,
1120
+ );
1117
1121
  }
1118
1122
 
1119
1123
  /**
@@ -1139,82 +1143,82 @@ function getOptionElements() {
1139
1143
  * @private
1140
1144
  */
1141
1145
  function calcAndSetOptionsDimension() {
1142
- const options = getOptionElements.call(this);
1143
- const container = this[optionsElementSymbol];
1144
- if (!(container instanceof HTMLElement && options instanceof NodeList)) {
1145
- return;
1146
- }
1147
-
1148
- let visible = 0;
1149
- let optionHeight = 0;
1150
- const max = this.getOption("showMaxOptions", 10);
1151
-
1152
- let scrollFlag = false;
1153
- for (const [, option] of Object.entries(options)) {
1154
- const computedStyle = getGlobal().getComputedStyle(option);
1155
- if (computedStyle.display === "none") continue;
1156
-
1157
- let h = option.getBoundingClientRect().height;
1158
- h += parseInt(computedStyle.getPropertyValue("margin-top"), 10);
1159
- h += parseInt(computedStyle.getPropertyValue("margin-bottom"), 10);
1160
- optionHeight += h;
1161
-
1162
- visible++;
1163
-
1164
- if (visible > max) {
1165
- break;
1166
- }
1167
- }
1168
-
1169
- if (visible > max) {
1170
- visible = max;
1171
- scrollFlag = true;
1172
- }
1173
-
1174
- if (visible === 0) {
1175
- if (this.getOption("options").length === 0) {
1176
- this.setOption(
1177
- "messages.emptyOptions",
1178
- this.getOption("labels.no-options-available"),
1179
- );
1180
- } else {
1181
- if (this.getOption("filter.mode") === FILTER_MODE_DISABLED) {
1182
- this.setOption(
1183
- "messages.emptyOptions",
1184
- this.getOption("labels.no-options-available"),
1185
- );
1186
- } else {
1187
- this.setOption(
1188
- "messages.emptyOptions",
1189
- this.getOption("labels.no-options-found"),
1190
- );
1191
- }
1192
- }
1193
- this[noOptionsAvailableElementSymbol].classList.remove("d-none");
1194
- } else {
1195
- this[noOptionsAvailableElementSymbol].classList.add("d-none");
1196
- }
1197
-
1198
- const styles = getGlobal().getComputedStyle(this[optionsElementSymbol]);
1199
- let padding = parseInt(styles.getPropertyValue("padding-top"), 10);
1200
- padding += parseInt(styles.getPropertyValue("padding-bottom"), 10);
1201
-
1202
- let margin = parseInt(styles.getPropertyValue("margin-top"), 10);
1203
- margin += parseInt(styles.getPropertyValue("margin-bottom"), 10);
1204
-
1205
- const containerHeight = optionHeight + padding + margin;
1206
- container.style.height = `${containerHeight}px`;
1207
-
1208
- if (scrollFlag === true) {
1209
- container.style.overflowY = "scroll";
1210
- } else {
1211
- container.style.overflowY = "auto";
1212
- }
1213
-
1214
- const domRect = this[controlElementSymbol].getBoundingClientRect();
1215
-
1216
- this[popperElementSymbol].style.width = `${domRect.width}px`;
1217
- container.style.overflowX = "auto";
1146
+ const options = getOptionElements.call(this);
1147
+ const container = this[optionsElementSymbol];
1148
+ if (!(container instanceof HTMLElement && options instanceof NodeList)) {
1149
+ return;
1150
+ }
1151
+
1152
+ let visible = 0;
1153
+ let optionHeight = 0;
1154
+ const max = this.getOption("showMaxOptions", 10);
1155
+
1156
+ let scrollFlag = false;
1157
+ for (const [, option] of Object.entries(options)) {
1158
+ const computedStyle = getGlobal().getComputedStyle(option);
1159
+ if (computedStyle.display === "none") continue;
1160
+
1161
+ let h = option.getBoundingClientRect().height;
1162
+ h += parseInt(computedStyle.getPropertyValue("margin-top"), 10);
1163
+ h += parseInt(computedStyle.getPropertyValue("margin-bottom"), 10);
1164
+ optionHeight += h;
1165
+
1166
+ visible++;
1167
+
1168
+ if (visible > max) {
1169
+ break;
1170
+ }
1171
+ }
1172
+
1173
+ if (visible > max) {
1174
+ visible = max;
1175
+ scrollFlag = true;
1176
+ }
1177
+
1178
+ if (visible === 0) {
1179
+ if (this.getOption("options").length === 0) {
1180
+ this.setOption(
1181
+ "messages.emptyOptions",
1182
+ this.getOption("labels.no-options-available"),
1183
+ );
1184
+ } else {
1185
+ if (this.getOption("filter.mode") === FILTER_MODE_DISABLED) {
1186
+ this.setOption(
1187
+ "messages.emptyOptions",
1188
+ this.getOption("labels.no-options-available"),
1189
+ );
1190
+ } else {
1191
+ this.setOption(
1192
+ "messages.emptyOptions",
1193
+ this.getOption("labels.no-options-found"),
1194
+ );
1195
+ }
1196
+ }
1197
+ this[noOptionsAvailableElementSymbol].classList.remove("d-none");
1198
+ } else {
1199
+ this[noOptionsAvailableElementSymbol].classList.add("d-none");
1200
+ }
1201
+
1202
+ const styles = getGlobal().getComputedStyle(this[optionsElementSymbol]);
1203
+ let padding = parseInt(styles.getPropertyValue("padding-top"), 10);
1204
+ padding += parseInt(styles.getPropertyValue("padding-bottom"), 10);
1205
+
1206
+ let margin = parseInt(styles.getPropertyValue("margin-top"), 10);
1207
+ margin += parseInt(styles.getPropertyValue("margin-bottom"), 10);
1208
+
1209
+ const containerHeight = optionHeight + padding + margin;
1210
+ container.style.height = `${containerHeight}px`;
1211
+
1212
+ if (scrollFlag === true) {
1213
+ container.style.overflowY = "scroll";
1214
+ } else {
1215
+ container.style.overflowY = "auto";
1216
+ }
1217
+
1218
+ const domRect = this[controlElementSymbol].getBoundingClientRect();
1219
+
1220
+ this[popperElementSymbol].style.width = `${domRect.width}px`;
1221
+ container.style.overflowX = "auto";
1218
1222
  }
1219
1223
 
1220
1224
  /**
@@ -1223,124 +1227,126 @@ function calcAndSetOptionsDimension() {
1223
1227
  * @throws {Error} no shadow-root is defined
1224
1228
  */
1225
1229
  function activateCurrentOption(direction) {
1226
- if (!this.shadowRoot) {
1227
- throw new Error("no shadow-root is defined");
1228
- }
1229
-
1230
- let focused = this.shadowRoot.querySelector(`[${ATTRIBUTE_PREFIX}focused]`);
1231
-
1232
- if (
1233
- !(focused instanceof HTMLElement) ||
1234
- focused.matches("[data-monster-visibility=hidden]")
1235
- ) {
1236
- for (const [, e] of Object.entries(
1237
- this.shadowRoot.querySelectorAll(`[${ATTRIBUTE_ROLE}=option]`),
1238
- )) {
1239
- if (e.matches("[data-monster-visibility=visible]")) {
1240
- focused = e;
1241
- break;
1242
- }
1243
- }
1244
- } else {
1245
- if (direction === FOCUS_DIRECTION_DOWN) {
1246
- while (focused.nextSibling) {
1247
- focused = focused.nextSibling;
1248
-
1249
- if (
1250
- focused instanceof HTMLElement &&
1251
- focused.hasAttribute(ATTRIBUTE_ROLE) &&
1252
- focused.getAttribute(ATTRIBUTE_ROLE) === "option" &&
1253
- focused.matches("[data-monster-visibility=visible]") &&
1254
- focused.matches(":not([data-monster-filtered=true])")
1255
- ) {
1256
- break;
1257
- }
1258
- }
1259
- } else {
1260
- let found = false;
1261
- while (focused.previousSibling) {
1262
- focused = focused.previousSibling;
1263
- if (
1264
- focused instanceof HTMLElement &&
1265
- focused.hasAttribute(ATTRIBUTE_ROLE) &&
1266
- focused.getAttribute(ATTRIBUTE_ROLE) === "option" &&
1267
- focused.matches("[data-monster-visibility=visible]") &&
1268
- focused.matches(":not([data-monster-filtered=true])")
1269
- ) {
1270
- found = true;
1271
- break;
1272
- }
1273
- }
1274
- if (found === false) {
1275
- focusFilter.call(this);
1276
- }
1277
- }
1278
- }
1279
-
1280
- new Processing(() => {
1281
- if (focused instanceof HTMLElement) {
1282
- this.shadowRoot
1283
- .querySelectorAll(`[${ATTRIBUTE_PREFIX}focused]`)
1284
- .forEach((e) => {
1285
- e.removeAttribute(`${ATTRIBUTE_PREFIX}focused`);
1286
- });
1287
-
1288
- focused.focus();
1289
- focused.setAttribute(`${ATTRIBUTE_PREFIX}focused`, true);
1290
- }
1291
- }).run().catch((e) => {
1292
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1293
- });
1230
+ if (!this.shadowRoot) {
1231
+ throw new Error("no shadow-root is defined");
1232
+ }
1233
+
1234
+ let focused = this.shadowRoot.querySelector(`[${ATTRIBUTE_PREFIX}focused]`);
1235
+
1236
+ if (
1237
+ !(focused instanceof HTMLElement) ||
1238
+ focused.matches("[data-monster-visibility=hidden]")
1239
+ ) {
1240
+ for (const [, e] of Object.entries(
1241
+ this.shadowRoot.querySelectorAll(`[${ATTRIBUTE_ROLE}=option]`),
1242
+ )) {
1243
+ if (e.matches("[data-monster-visibility=visible]")) {
1244
+ focused = e;
1245
+ break;
1246
+ }
1247
+ }
1248
+ } else {
1249
+ if (direction === FOCUS_DIRECTION_DOWN) {
1250
+ while (focused.nextSibling) {
1251
+ focused = focused.nextSibling;
1252
+
1253
+ if (
1254
+ focused instanceof HTMLElement &&
1255
+ focused.hasAttribute(ATTRIBUTE_ROLE) &&
1256
+ focused.getAttribute(ATTRIBUTE_ROLE) === "option" &&
1257
+ focused.matches("[data-monster-visibility=visible]") &&
1258
+ focused.matches(":not([data-monster-filtered=true])")
1259
+ ) {
1260
+ break;
1261
+ }
1262
+ }
1263
+ } else {
1264
+ let found = false;
1265
+ while (focused.previousSibling) {
1266
+ focused = focused.previousSibling;
1267
+ if (
1268
+ focused instanceof HTMLElement &&
1269
+ focused.hasAttribute(ATTRIBUTE_ROLE) &&
1270
+ focused.getAttribute(ATTRIBUTE_ROLE) === "option" &&
1271
+ focused.matches("[data-monster-visibility=visible]") &&
1272
+ focused.matches(":not([data-monster-filtered=true])")
1273
+ ) {
1274
+ found = true;
1275
+ break;
1276
+ }
1277
+ }
1278
+ if (found === false) {
1279
+ focusFilter.call(this);
1280
+ }
1281
+ }
1282
+ }
1283
+
1284
+ new Processing(() => {
1285
+ if (focused instanceof HTMLElement) {
1286
+ this.shadowRoot
1287
+ .querySelectorAll(`[${ATTRIBUTE_PREFIX}focused]`)
1288
+ .forEach((e) => {
1289
+ e.removeAttribute(`${ATTRIBUTE_PREFIX}focused`);
1290
+ });
1291
+
1292
+ focused.focus();
1293
+ focused.setAttribute(`${ATTRIBUTE_PREFIX}focused`, true);
1294
+ }
1295
+ })
1296
+ .run()
1297
+ .catch((e) => {
1298
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1299
+ });
1294
1300
  }
1295
1301
 
1296
1302
  /**
1297
1303
  * @private
1298
1304
  */
1299
1305
  function filterOptions() {
1300
- new Processing(() => {
1301
- let filterValue;
1302
-
1303
- switch (this.getOption("filter.position")) {
1304
- case FILTER_POSITION_INLINE:
1305
- if (this[inlineFilterElementSymbol] instanceof HTMLElement) {
1306
- filterValue = this[inlineFilterElementSymbol].value.toLowerCase();
1307
- } else {
1308
- return;
1309
- }
1310
-
1311
- break;
1312
- case FILTER_POSITION_POPPER:
1313
- default:
1314
- if (this[popperFilterElementSymbol] instanceof HTMLInputElement) {
1315
- filterValue = this[popperFilterElementSymbol].value.toLowerCase();
1316
- } else {
1317
- return;
1318
- }
1319
- }
1320
-
1321
- const options = this.getOption("options");
1322
- for (const [i, option] of Object.entries(options)) {
1323
- if (option.label.toLowerCase().indexOf(filterValue) === -1) {
1324
- this.setOption(`options.${i}.filtered`, "true");
1325
- } else {
1326
- this.setOption(`options.${i}.filtered`, undefined);
1327
- }
1328
- }
1329
- })
1330
- .run()
1331
- .then(() => {
1332
- new Processing(100, () => {
1333
- calcAndSetOptionsDimension.call(this);
1334
- focusFilter.call(this);
1335
- })
1336
- .run()
1337
- .catch((e) => {
1338
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1339
- });
1340
- })
1341
- .catch((e) => {
1342
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1343
- });
1306
+ new Processing(() => {
1307
+ let filterValue;
1308
+
1309
+ switch (this.getOption("filter.position")) {
1310
+ case FILTER_POSITION_INLINE:
1311
+ if (this[inlineFilterElementSymbol] instanceof HTMLElement) {
1312
+ filterValue = this[inlineFilterElementSymbol].value.toLowerCase();
1313
+ } else {
1314
+ return;
1315
+ }
1316
+
1317
+ break;
1318
+ case FILTER_POSITION_POPPER:
1319
+ default:
1320
+ if (this[popperFilterElementSymbol] instanceof HTMLInputElement) {
1321
+ filterValue = this[popperFilterElementSymbol].value.toLowerCase();
1322
+ } else {
1323
+ return;
1324
+ }
1325
+ }
1326
+
1327
+ const options = this.getOption("options");
1328
+ for (const [i, option] of Object.entries(options)) {
1329
+ if (option.label.toLowerCase().indexOf(filterValue) === -1) {
1330
+ this.setOption(`options.${i}.filtered`, "true");
1331
+ } else {
1332
+ this.setOption(`options.${i}.filtered`, undefined);
1333
+ }
1334
+ }
1335
+ })
1336
+ .run()
1337
+ .then(() => {
1338
+ new Processing(100, () => {
1339
+ calcAndSetOptionsDimension.call(this);
1340
+ focusFilter.call(this);
1341
+ })
1342
+ .run()
1343
+ .catch((e) => {
1344
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1345
+ });
1346
+ })
1347
+ .catch((e) => {
1348
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1349
+ });
1344
1350
  }
1345
1351
 
1346
1352
  /**
@@ -1348,37 +1354,37 @@ function filterOptions() {
1348
1354
  * @param {Event} event
1349
1355
  */
1350
1356
  function handleFilterKeyboardEvents(event) {
1351
- const shiftKey = event?.["shiftKey"];
1352
-
1353
- switch (event?.["code"]) {
1354
- case "Tab":
1355
- activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1356
- event.preventDefault();
1357
- break;
1358
- case "Escape":
1359
- toggle.call(this);
1360
- event.preventDefault();
1361
- break;
1362
- case "Tab" && shiftKey === true:
1363
- case "ArrowUp":
1364
- activateCurrentOption.call(this, FOCUS_DIRECTION_UP);
1365
- event.preventDefault();
1366
- break;
1367
- case "Tab" && !shiftKey:
1368
- case "ArrowDown":
1369
- activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1370
- event.preventDefault();
1371
- break;
1372
- default:
1373
- if (
1374
- this.getOption("features.lazyLoad") === true &&
1375
- this[lazyLoadDoneSymbol] !== true
1376
- ) {
1377
- this.click();
1378
- }
1379
-
1380
- handleFilterKeyEvents.call(this);
1381
- }
1357
+ const shiftKey = event?.["shiftKey"];
1358
+
1359
+ switch (event?.["code"]) {
1360
+ case "Tab":
1361
+ activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1362
+ event.preventDefault();
1363
+ break;
1364
+ case "Escape":
1365
+ toggle.call(this);
1366
+ event.preventDefault();
1367
+ break;
1368
+ case "Tab" && shiftKey === true:
1369
+ case "ArrowUp":
1370
+ activateCurrentOption.call(this, FOCUS_DIRECTION_UP);
1371
+ event.preventDefault();
1372
+ break;
1373
+ case "Tab" && !shiftKey:
1374
+ case "ArrowDown":
1375
+ activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1376
+ event.preventDefault();
1377
+ break;
1378
+ default:
1379
+ if (
1380
+ this.getOption("features.lazyLoad") === true &&
1381
+ this[lazyLoadDoneSymbol] !== true
1382
+ ) {
1383
+ this.click();
1384
+ }
1385
+
1386
+ handleFilterKeyEvents.call(this);
1387
+ }
1382
1388
  }
1383
1389
 
1384
1390
  /**
@@ -1397,63 +1403,63 @@ function handleFilterKeyboardEvents(event) {
1397
1403
  * @returns {void} This method does not return anything.
1398
1404
  */
1399
1405
  function handleFilterKeyEvents() {
1400
- if (this[keyFilterEventSymbol] instanceof DeadMansSwitch) {
1401
- try {
1402
- this[keyFilterEventSymbol].touch();
1403
- return;
1404
- } catch (e) {
1405
- delete this[keyFilterEventSymbol];
1406
- }
1407
- }
1408
-
1409
- this[keyFilterEventSymbol] = new DeadMansSwitch(200, () => {
1410
- if (this.getOption("filter.mode") !== FILTER_MODE_REMOTE) {
1411
- filterOptions.call(this);
1412
- } else {
1413
- filterFromRemote.call(this).catch((e) => {
1414
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1415
- });
1416
- }
1417
-
1418
- delete this[keyFilterEventSymbol];
1419
- });
1406
+ if (this[keyFilterEventSymbol] instanceof DeadMansSwitch) {
1407
+ try {
1408
+ this[keyFilterEventSymbol].touch();
1409
+ return;
1410
+ } catch (e) {
1411
+ delete this[keyFilterEventSymbol];
1412
+ }
1413
+ }
1414
+
1415
+ this[keyFilterEventSymbol] = new DeadMansSwitch(200, () => {
1416
+ if (this.getOption("filter.mode") !== FILTER_MODE_REMOTE) {
1417
+ filterOptions.call(this);
1418
+ } else {
1419
+ filterFromRemote.call(this).catch((e) => {
1420
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1421
+ });
1422
+ }
1423
+
1424
+ delete this[keyFilterEventSymbol];
1425
+ });
1420
1426
  }
1421
1427
 
1422
1428
  /**
1423
1429
  * @private
1424
1430
  */
1425
1431
  function filterFromRemote() {
1426
- if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) {
1427
- return;
1428
- }
1429
-
1430
- const optionUrl = this.getOption("url");
1431
- if (!optionUrl) {
1432
- addAttributeToken(
1433
- this,
1434
- ATTRIBUTE_ERRORMESSAGE,
1435
- "Missing URL for Remote Filter.",
1436
- );
1437
- return;
1438
- }
1439
-
1440
- return new Processing(() => {
1441
- const filterValue = encodeURI(
1442
- this[inlineFilterElementSymbol].value.toLowerCase(),
1443
- );
1444
- let url = optionUrl;
1445
- if (filterValue.length > 0) {
1446
- url = new Formatter({filter: filterValue}).format(optionUrl);
1447
- }
1448
-
1449
- this.fetch(url)
1450
- .then(() => {
1451
- checkOptionState.call(this);
1452
- })
1453
- .catch((e) => {
1454
- throw e;
1455
- });
1456
- }).run();
1432
+ if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) {
1433
+ return;
1434
+ }
1435
+
1436
+ const optionUrl = this.getOption("url");
1437
+ if (!optionUrl) {
1438
+ addAttributeToken(
1439
+ this,
1440
+ ATTRIBUTE_ERRORMESSAGE,
1441
+ "Missing URL for Remote Filter.",
1442
+ );
1443
+ return;
1444
+ }
1445
+
1446
+ return new Processing(() => {
1447
+ const filterValue = encodeURI(
1448
+ this[inlineFilterElementSymbol].value.toLowerCase(),
1449
+ );
1450
+ let url = optionUrl;
1451
+ if (filterValue.length > 0) {
1452
+ url = new Formatter({ filter: filterValue }).format(optionUrl);
1453
+ }
1454
+
1455
+ this.fetch(url)
1456
+ .then(() => {
1457
+ checkOptionState.call(this);
1458
+ })
1459
+ .catch((e) => {
1460
+ throw e;
1461
+ });
1462
+ }).run();
1457
1463
  }
1458
1464
 
1459
1465
  /**
@@ -1462,45 +1468,45 @@ function filterFromRemote() {
1462
1468
  * @private
1463
1469
  */
1464
1470
  function handleOptionKeyboardEvents(event) {
1465
- const shiftKey = event?.["shiftKey"];
1466
-
1467
- switch (event?.["code"]) {
1468
- case "Escape":
1469
- toggle.call(this);
1470
- event.preventDefault();
1471
- break;
1472
- case "Enter":
1473
- case "Space":
1474
- const path = event.composedPath();
1475
- const element = path?.[0];
1476
-
1477
- fireEvent(element.getElementsByTagName("input"), "click");
1478
- event.preventDefault();
1479
- break;
1480
-
1481
- case "Tab" && shiftKey === true:
1482
- case "ArrowUp":
1483
- activateCurrentOption.call(this, FOCUS_DIRECTION_UP);
1484
- event.preventDefault();
1485
- break;
1486
-
1487
- case "Tab" && !shiftKey:
1488
- case "ArrowLeft":
1489
- case "ArrowRight":
1490
- // handled by tree select
1491
- break;
1492
- case "ArrowDown":
1493
- activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1494
- event.preventDefault();
1495
- break;
1496
- default:
1497
- const p = event.composedPath();
1498
- if (p?.[0] instanceof HTMLInputElement) {
1499
- return;
1500
- }
1501
- focusFilter.call(this);
1502
- break;
1503
- }
1471
+ const shiftKey = event?.["shiftKey"];
1472
+
1473
+ switch (event?.["code"]) {
1474
+ case "Escape":
1475
+ toggle.call(this);
1476
+ event.preventDefault();
1477
+ break;
1478
+ case "Enter":
1479
+ case "Space":
1480
+ const path = event.composedPath();
1481
+ const element = path?.[0];
1482
+
1483
+ fireEvent(element.getElementsByTagName("input"), "click");
1484
+ event.preventDefault();
1485
+ break;
1486
+
1487
+ case "Tab" && shiftKey === true:
1488
+ case "ArrowUp":
1489
+ activateCurrentOption.call(this, FOCUS_DIRECTION_UP);
1490
+ event.preventDefault();
1491
+ break;
1492
+
1493
+ case "Tab" && !shiftKey:
1494
+ case "ArrowLeft":
1495
+ case "ArrowRight":
1496
+ // handled by tree select
1497
+ break;
1498
+ case "ArrowDown":
1499
+ activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
1500
+ event.preventDefault();
1501
+ break;
1502
+ default:
1503
+ const p = event.composedPath();
1504
+ if (p?.[0] instanceof HTMLInputElement) {
1505
+ return;
1506
+ }
1507
+ focusFilter.call(this);
1508
+ break;
1509
+ }
1504
1510
  }
1505
1511
 
1506
1512
  /**
@@ -1508,33 +1514,33 @@ function handleOptionKeyboardEvents(event) {
1508
1514
  * @returns {string}
1509
1515
  */
1510
1516
  function getFilterMode() {
1511
- switch (this.getOption("filter.mode")) {
1512
- case FILTER_MODE_OPTIONS:
1513
- return FILTER_MODE_OPTIONS;
1514
- case FILTER_MODE_REMOTE:
1515
- return FILTER_MODE_REMOTE;
1516
- default:
1517
- return FILTER_MODE_DISABLED;
1518
- }
1517
+ switch (this.getOption("filter.mode")) {
1518
+ case FILTER_MODE_OPTIONS:
1519
+ return FILTER_MODE_OPTIONS;
1520
+ case FILTER_MODE_REMOTE:
1521
+ return FILTER_MODE_REMOTE;
1522
+ default:
1523
+ return FILTER_MODE_DISABLED;
1524
+ }
1519
1525
  }
1520
1526
 
1521
1527
  /**
1522
1528
  * @private
1523
1529
  */
1524
1530
  function blurFilter() {
1525
- if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) {
1526
- return;
1527
- }
1531
+ if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) {
1532
+ return;
1533
+ }
1528
1534
 
1529
- if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
1530
- return;
1531
- }
1535
+ if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
1536
+ return;
1537
+ }
1532
1538
 
1533
- this[popperFilterContainerElementSymbol].classList.remove("active");
1534
- this[popperFilterContainerElementSymbol].blur();
1539
+ this[popperFilterContainerElementSymbol].classList.remove("active");
1540
+ this[popperFilterContainerElementSymbol].blur();
1535
1541
 
1536
- this[inlineFilterElementSymbol].classList.remove("active");
1537
- this[inlineFilterElementSymbol].blur();
1542
+ this[inlineFilterElementSymbol].classList.remove("active");
1543
+ this[inlineFilterElementSymbol].blur();
1538
1544
  }
1539
1545
 
1540
1546
  /**
@@ -1542,29 +1548,29 @@ function blurFilter() {
1542
1548
  * @param focusOptions
1543
1549
  */
1544
1550
  function focusPopperFilter(focusOptions) {
1545
- this[popperFilterContainerElementSymbol].classList.remove("d-none");
1546
- this[popperFilterElementSymbol].classList.add("active");
1547
- this[inlineFilterElementSymbol].classList.remove("active");
1548
- this[inlineFilterElementSymbol].classList.add("d-none");
1549
-
1550
- if (!(this[popperFilterElementSymbol] instanceof HTMLElement)) {
1551
- addAttributeToken(
1552
- this,
1553
- ATTRIBUTE_ERRORMESSAGE,
1554
- "Missing Popper Filter Element.",
1555
- );
1556
- return;
1557
- }
1558
-
1559
- // visibility is set to visible, because focus() does not work on invisible elements
1560
- // and the class definition is assigned later in the processing
1561
- setTimeout(() => {
1562
- if (focusOptions === undefined || focusOptions === null) {
1563
- this[popperFilterElementSymbol].focus();
1564
- } else {
1565
- this[popperFilterElementSymbol].focus(focusOptions);
1566
- }
1567
- }, 100);
1551
+ this[popperFilterContainerElementSymbol].classList.remove("d-none");
1552
+ this[popperFilterElementSymbol].classList.add("active");
1553
+ this[inlineFilterElementSymbol].classList.remove("active");
1554
+ this[inlineFilterElementSymbol].classList.add("d-none");
1555
+
1556
+ if (!(this[popperFilterElementSymbol] instanceof HTMLElement)) {
1557
+ addAttributeToken(
1558
+ this,
1559
+ ATTRIBUTE_ERRORMESSAGE,
1560
+ "Missing Popper Filter Element.",
1561
+ );
1562
+ return;
1563
+ }
1564
+
1565
+ // visibility is set to visible, because focus() does not work on invisible elements
1566
+ // and the class definition is assigned later in the processing
1567
+ setTimeout(() => {
1568
+ if (focusOptions === undefined || focusOptions === null) {
1569
+ this[popperFilterElementSymbol].focus();
1570
+ } else {
1571
+ this[popperFilterElementSymbol].focus(focusOptions);
1572
+ }
1573
+ }, 100);
1568
1574
  }
1569
1575
 
1570
1576
  /**
@@ -1572,44 +1578,44 @@ function focusPopperFilter(focusOptions) {
1572
1578
  * @param focusOptions
1573
1579
  */
1574
1580
  function focusInlineFilter(focusOptions) {
1575
- const options = this.getOption("options");
1576
- if (
1577
- (!isArray(options) || options.length === 0) &&
1578
- this.getOption("filter.mode") !== FILTER_MODE_REMOTE
1579
- ) {
1580
- return;
1581
- }
1582
-
1583
- this[popperFilterContainerElementSymbol].classList.add("d-none");
1584
- this[inlineFilterElementSymbol].classList.add("active");
1585
- this[inlineFilterElementSymbol].classList.remove("d-none");
1586
-
1587
- // visibility is set to visible, because focus() does not work on invisible elements
1588
- // and the class definition is assigned later in the processing
1589
- setTimeout(() => {
1590
- if (focusOptions === undefined || focusOptions === null) {
1591
- this[inlineFilterElementSymbol].focus();
1592
- } else {
1593
- this[inlineFilterElementSymbol].focus(focusOptions);
1594
- }
1595
- }, 100);
1581
+ const options = this.getOption("options");
1582
+ if (
1583
+ (!isArray(options) || options.length === 0) &&
1584
+ this.getOption("filter.mode") !== FILTER_MODE_REMOTE
1585
+ ) {
1586
+ return;
1587
+ }
1588
+
1589
+ this[popperFilterContainerElementSymbol].classList.add("d-none");
1590
+ this[inlineFilterElementSymbol].classList.add("active");
1591
+ this[inlineFilterElementSymbol].classList.remove("d-none");
1592
+
1593
+ // visibility is set to visible, because focus() does not work on invisible elements
1594
+ // and the class definition is assigned later in the processing
1595
+ setTimeout(() => {
1596
+ if (focusOptions === undefined || focusOptions === null) {
1597
+ this[inlineFilterElementSymbol].focus();
1598
+ } else {
1599
+ this[inlineFilterElementSymbol].focus(focusOptions);
1600
+ }
1601
+ }, 100);
1596
1602
  }
1597
1603
 
1598
1604
  /**
1599
1605
  * @private
1600
1606
  */
1601
1607
  function focusFilter(focusOptions) {
1602
- if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
1603
- this[popperFilterContainerElementSymbol].classList.add("d-none");
1604
- this[inlineFilterElementSymbol].classList.add("d-none");
1605
- return;
1606
- }
1608
+ if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
1609
+ this[popperFilterContainerElementSymbol].classList.add("d-none");
1610
+ this[inlineFilterElementSymbol].classList.add("d-none");
1611
+ return;
1612
+ }
1607
1613
 
1608
- if (this.getOption("filter.position") === FILTER_POSITION_INLINE) {
1609
- return focusInlineFilter.call(this, focusOptions);
1610
- }
1614
+ if (this.getOption("filter.position") === FILTER_POSITION_INLINE) {
1615
+ return focusInlineFilter.call(this, focusOptions);
1616
+ }
1611
1617
 
1612
- return focusPopperFilter.call(this, focusOptions);
1618
+ return focusPopperFilter.call(this, focusOptions);
1613
1619
  }
1614
1620
 
1615
1621
  /**
@@ -1619,39 +1625,39 @@ function focusFilter(focusOptions) {
1619
1625
  * @throws {Error} unsupported type
1620
1626
  */
1621
1627
  function gatherState() {
1622
- const type = this.getOption("type");
1623
- if (["radio", "checkbox"].indexOf(type) === -1) {
1624
- throw new Error("unsupported type");
1625
- }
1626
-
1627
- if (!this.shadowRoot) {
1628
- throw new Error("no shadow-root is defined");
1629
- }
1630
-
1631
- const selection = [];
1632
- const elements = this.shadowRoot.querySelectorAll(
1633
- `input[type=${type}]:checked`,
1634
- );
1635
- for (const e of elements) {
1636
- selection.push({
1637
- label: getSelectionLabel.call(this, e.value),
1638
- value: e.value,
1639
- });
1640
- }
1641
-
1642
- setSelection
1643
- .call(this, selection)
1644
- .then(() => {
1645
- })
1646
- .catch((e) => {
1647
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
1648
- });
1649
-
1650
- if (this.getOption("features.closeOnSelect") === true) {
1651
- toggle.call(this);
1652
- }
1653
-
1654
- return this;
1628
+ const type = this.getOption("type");
1629
+ if (["radio", "checkbox"].indexOf(type) === -1) {
1630
+ throw new Error("unsupported type");
1631
+ }
1632
+
1633
+ if (!this.shadowRoot) {
1634
+ throw new Error("no shadow-root is defined");
1635
+ }
1636
+
1637
+ const selection = [];
1638
+ const elements = this.shadowRoot.querySelectorAll(
1639
+ `input[type=${type}]:checked`,
1640
+ );
1641
+
1642
+ for (const e of elements) {
1643
+ selection.push({
1644
+ label: getSelectionLabel.call(this, e.value),
1645
+ value: e.value,
1646
+ });
1647
+ }
1648
+
1649
+ setSelection
1650
+ .call(this, selection)
1651
+ .then(() => {})
1652
+ .catch((e) => {
1653
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
1654
+ });
1655
+
1656
+ if (this.getOption("features.closeOnSelect") === true) {
1657
+ toggle.call(this);
1658
+ }
1659
+
1660
+ return this;
1655
1661
  }
1656
1662
 
1657
1663
  /**
@@ -1660,118 +1666,120 @@ function gatherState() {
1660
1666
  * @throws {Error} unsupported type
1661
1667
  */
1662
1668
  function clearSelection() {
1663
- const type = this.getOption("type");
1664
- if (["radio", "checkbox"].indexOf(type) === -1) {
1665
- throw new Error("unsupported type");
1666
- }
1667
-
1668
- if (!this.shadowRoot) {
1669
- throw new Error("no shadow-root is defined");
1670
- }
1671
-
1672
- setSelection
1673
- .call(this, [])
1674
- .then(() => {
1675
- })
1676
- .catch((e) => {
1677
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
1678
- });
1669
+ const type = this.getOption("type");
1670
+ if (["radio", "checkbox"].indexOf(type) === -1) {
1671
+ throw new Error("unsupported type");
1672
+ }
1673
+
1674
+ if (!this.shadowRoot) {
1675
+ throw new Error("no shadow-root is defined");
1676
+ }
1677
+
1678
+ setSelection
1679
+ .call(this, [])
1680
+ .then(() => {})
1681
+ .catch((e) => {
1682
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
1683
+ });
1679
1684
  }
1680
1685
 
1681
1686
  /**
1682
1687
  * @private
1683
1688
  */
1684
1689
  function areOptionsAvailableAndInit() {
1685
- // prevent multiple calls
1686
- if (this[areOptionsAvailableAndInitSymbol] === undefined) {
1687
- this[areOptionsAvailableAndInitSymbol] = 0;
1688
- }
1689
-
1690
- if (this[areOptionsAvailableAndInitSymbol] > 0) {
1691
- this[areOptionsAvailableAndInitSymbol]--;
1692
- return true;
1693
- }
1694
-
1695
- this[areOptionsAvailableAndInitSymbol]++;
1696
-
1697
- const options = this.getOption("options");
1698
-
1699
- if (
1700
- options === undefined ||
1701
- options === null ||
1702
- (isArray(options) && options.length === 0)
1703
- ) {
1704
- setStatusOrRemoveBadges.call(this, "empty");
1705
-
1706
- hide.call(this);
1707
-
1708
- let msg = this.getOption("labels.no-options-available");
1709
-
1710
- if (
1711
- this.getOption("url") !== null &&
1712
- this.getOption("features.lazyLoad") === true &&
1713
- this[lazyLoadDoneSymbol] !== true
1714
- ) {
1715
- msg = this.getOption("labels.click-to-load-options");
1716
- }
1717
-
1718
- this.setOption("messages.control", msg);
1719
- this.setOption("messages.summary", "");
1720
- this.setOption("selection", []);
1721
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage);
1722
- return false;
1723
- }
1724
-
1725
- const selections = this.getOption("selection");
1726
- if (
1727
- selections === undefined ||
1728
- selections === null ||
1729
- selections.length === 0
1730
- ) {
1731
- this.setOption(
1732
- "messages.control",
1733
- this.getOption("labels.select-an-option"),
1734
- );
1735
- } else {
1736
- this.setOption("messages.control", "");
1737
- }
1738
-
1739
- this.setOption("messages.summary", setSummaryAndControlText.call(this));
1740
-
1741
- let updated = false;
1742
- let valueCounter = 1;
1743
- for (const option of options) {
1744
- if (option?.visibility === undefined) {
1745
- option.visibility = "visible";
1746
- updated = true;
1747
- }
1748
-
1749
- if (option?.value === undefined && option?.label === undefined) {
1750
- option.value = `${valueCounter++}`;
1751
- option.label = option.value;
1752
- updated = true;
1753
- continue;
1754
- }
1755
-
1756
- if (option?.value === undefined) {
1757
- option.value = option.label;
1758
- updated = true;
1759
- }
1760
-
1761
- if (option?.label === undefined) {
1762
- option.label = option.value;
1763
- updated = true;
1764
- }
1765
- }
1766
-
1767
- if (updated) {
1768
- this.setOption("options", options);
1769
- }
1770
-
1771
- setStatusOrRemoveBadges.call(this, "status");
1772
-
1773
- removeAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage);
1774
- return true;
1690
+ // prevent multiple calls
1691
+ if (this[areOptionsAvailableAndInitSymbol] === undefined) {
1692
+ this[areOptionsAvailableAndInitSymbol] = 0;
1693
+ }
1694
+
1695
+ if (this[areOptionsAvailableAndInitSymbol] > 0) {
1696
+ this[areOptionsAvailableAndInitSymbol]--;
1697
+ return true;
1698
+ }
1699
+
1700
+ this[areOptionsAvailableAndInitSymbol]++;
1701
+
1702
+ const options = this.getOption("options");
1703
+
1704
+ if (
1705
+ options === undefined ||
1706
+ options === null ||
1707
+ (isArray(options) && options.length === 0)
1708
+ ) {
1709
+ setStatusOrRemoveBadges.call(this, "empty");
1710
+
1711
+ hide.call(this);
1712
+
1713
+ let msg = this.getOption("labels.no-options-available");
1714
+
1715
+ if (
1716
+ this.getOption("url") !== null &&
1717
+ this.getOption("features.lazyLoad") === true &&
1718
+ this[lazyLoadDoneSymbol] !== true
1719
+ ) {
1720
+ msg = this.getOption("labels.click-to-load-options");
1721
+ }
1722
+
1723
+ this.setOption("messages.control", msg);
1724
+ this.setOption("messages.summary", "");
1725
+
1726
+ if (this.getOption("features.emptyValueIfNoOptions") === true) {
1727
+ this.value = "";
1728
+ }
1729
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage);
1730
+ return false;
1731
+ }
1732
+
1733
+ const selections = this.getOption("selection");
1734
+ if (
1735
+ selections === undefined ||
1736
+ selections === null ||
1737
+ selections.length === 0
1738
+ ) {
1739
+ this.setOption(
1740
+ "messages.control",
1741
+ this.getOption("labels.select-an-option"),
1742
+ );
1743
+ } else {
1744
+ this.setOption("messages.control", "");
1745
+ }
1746
+
1747
+ this.setOption("messages.summary", setSummaryAndControlText.call(this));
1748
+
1749
+ let updated = false;
1750
+ let valueCounter = 1;
1751
+ for (const option of options) {
1752
+ if (option?.visibility === undefined) {
1753
+ option.visibility = "visible";
1754
+ updated = true;
1755
+ }
1756
+
1757
+ if (option?.value === undefined && option?.label === undefined) {
1758
+ option.value = `${valueCounter++}`;
1759
+ option.label = option.value;
1760
+ updated = true;
1761
+ continue;
1762
+ }
1763
+
1764
+ if (option?.value === undefined) {
1765
+ option.value = option.label;
1766
+ updated = true;
1767
+ }
1768
+
1769
+ if (option?.label === undefined) {
1770
+ option.label = option.value;
1771
+ updated = true;
1772
+ }
1773
+ }
1774
+
1775
+ if (updated) {
1776
+ this.setOption("options", options);
1777
+ }
1778
+
1779
+ setStatusOrRemoveBadges.call(this, "status");
1780
+
1781
+ removeAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage);
1782
+ return true;
1775
1783
  }
1776
1784
 
1777
1785
  /**
@@ -1779,30 +1787,30 @@ function areOptionsAvailableAndInit() {
1779
1787
  * @throws {Error} no shadow-root is defined
1780
1788
  */
1781
1789
  function checkOptionState() {
1782
- if (!this.shadowRoot) {
1783
- throw new Error("no shadow-root is defined");
1784
- }
1785
-
1786
- const elements = this.shadowRoot.querySelectorAll(
1787
- `[${ATTRIBUTE_ROLE}=option] input`,
1788
- );
1789
-
1790
- let selection = this.getOption("selection");
1791
- if (!isArray(selection)) {
1792
- selection = [];
1793
- }
1794
-
1795
- const checkedValues = selection.map((a) => {
1796
- return a.value;
1797
- });
1798
-
1799
- for (const e of elements) {
1800
- if (checkedValues.indexOf(e.value) !== -1) {
1801
- if (e.checked !== true) e.checked = true;
1802
- } else {
1803
- if (e.checked !== false) e.checked = false;
1804
- }
1805
- }
1790
+ if (!this.shadowRoot) {
1791
+ throw new Error("no shadow-root is defined");
1792
+ }
1793
+
1794
+ const elements = this.shadowRoot.querySelectorAll(
1795
+ `[${ATTRIBUTE_ROLE}=option] input`,
1796
+ );
1797
+
1798
+ let selection = this.getOption("selection");
1799
+ if (!isArray(selection)) {
1800
+ selection = [];
1801
+ }
1802
+
1803
+ const checkedValues = selection.map((a) => {
1804
+ return a.value;
1805
+ });
1806
+
1807
+ for (const e of elements) {
1808
+ if (checkedValues.indexOf(e.value) !== -1) {
1809
+ if (e.checked !== true) e.checked = true;
1810
+ } else {
1811
+ if (e.checked !== false) e.checked = false;
1812
+ }
1813
+ }
1806
1814
  }
1807
1815
 
1808
1816
  /**
@@ -1811,41 +1819,41 @@ function checkOptionState() {
1811
1819
  * @return {Object}
1812
1820
  */
1813
1821
  function convertValueToSelection(value) {
1814
- const selection = [];
1815
-
1816
- if (isString(value)) {
1817
- value = value
1818
- .split(",")
1819
- .map((a) => {
1820
- return a.trim();
1821
- })
1822
- .filter((a) => {
1823
- return a !== "";
1824
- });
1825
- }
1826
-
1827
- if (isString(value) || isInteger(value)) {
1828
- selection.push({
1829
- label: getSelectionLabel.call(this, value),
1830
- value: value,
1831
- });
1832
- } else if (isArray(value)) {
1833
- for (const v of value) {
1834
- selection.push({
1835
- label: getSelectionLabel.call(this, v),
1836
- value: v,
1837
- });
1838
- }
1839
-
1840
- value = value.join(",");
1841
- } else {
1842
- throw new Error("unsupported type");
1843
- }
1844
-
1845
- return {
1846
- selection: selection,
1847
- value: value,
1848
- };
1822
+ const selection = [];
1823
+
1824
+ if (isString(value)) {
1825
+ value = value
1826
+ .split(",")
1827
+ .map((a) => {
1828
+ return a.trim();
1829
+ })
1830
+ .filter((a) => {
1831
+ return a !== "";
1832
+ });
1833
+ }
1834
+
1835
+ if (isString(value) || isInteger(value)) {
1836
+ selection.push({
1837
+ label: getSelectionLabel.call(this, value),
1838
+ value: value,
1839
+ });
1840
+ } else if (isArray(value)) {
1841
+ for (const v of value) {
1842
+ selection.push({
1843
+ label: getSelectionLabel.call(this, v),
1844
+ value: v,
1845
+ });
1846
+ }
1847
+
1848
+ value = value.join(",");
1849
+ } else {
1850
+ throw new Error("unsupported type");
1851
+ }
1852
+
1853
+ return {
1854
+ selection: selection,
1855
+ value: value,
1856
+ };
1849
1857
  }
1850
1858
 
1851
1859
  /**
@@ -1854,22 +1862,22 @@ function convertValueToSelection(value) {
1854
1862
  * @return {string}
1855
1863
  */
1856
1864
  function convertSelectionToValue(selection) {
1857
- const value = [];
1858
-
1859
- if (isArray(selection)) {
1860
- for (const obj of selection) {
1861
- const v = obj?.["value"];
1862
- if (v !== undefined) value.push(v);
1863
- }
1864
- }
1865
-
1866
- if (value.length === 0) {
1867
- return "";
1868
- } else if (value.length === 1) {
1869
- return value.pop();
1870
- }
1871
-
1872
- return value.join(",");
1865
+ const value = [];
1866
+
1867
+ if (isArray(selection)) {
1868
+ for (const obj of selection) {
1869
+ const v = obj?.["value"];
1870
+ if (v !== undefined) value.push(v);
1871
+ }
1872
+ }
1873
+
1874
+ if (value.length === 0) {
1875
+ return "";
1876
+ } else if (value.length === 1) {
1877
+ return value.pop();
1878
+ }
1879
+
1880
+ return value.join(",");
1873
1881
  }
1874
1882
 
1875
1883
  /**
@@ -1879,56 +1887,58 @@ function convertSelectionToValue(selection) {
1879
1887
  * @throws {Error} no shadow-root is defined
1880
1888
  */
1881
1889
  function setSelection(selection) {
1882
- if (isString(selection)) {
1883
- const result = convertValueToSelection.call(this, selection);
1884
- selection = result?.selection;
1885
- } else if (selection === undefined) {
1886
- selection = [];
1887
- }
1888
-
1889
- this.setOption("selection", validateArray(selection));
1890
- checkOptionState.call(this);
1891
-
1892
- try {
1893
- this?.setFormValue(this.value);
1894
- } catch (e) {
1895
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1896
- }
1897
-
1898
- fireCustomEvent(this, "monster-selected", {
1899
- selection,
1900
- });
1901
-
1902
- return new Processing(() => {
1903
- const CLASSNAME = "selected";
1904
-
1905
- if (!this.shadowRoot) {
1906
- throw new Error("no shadow-root is defined");
1907
- }
1908
-
1909
- const notSelected = this.shadowRoot.querySelectorAll(":not(:checked)");
1910
-
1911
- if (notSelected) {
1912
- notSelected.forEach((node) => {
1913
- const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`);
1914
- if (parent) {
1915
- parent.classList.remove(CLASSNAME);
1916
- }
1917
- });
1918
- }
1919
-
1920
- const selected = this.shadowRoot.querySelectorAll(":checked");
1921
- if (selected) {
1922
- selected.forEach((node) => {
1923
- const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`);
1924
- if (parent) {
1925
- parent.classList.add(CLASSNAME);
1926
- }
1927
- });
1928
- }
1929
- }).run().catch((e) => {
1930
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1931
- });
1890
+ if (isString(selection)) {
1891
+ const result = convertValueToSelection.call(this, selection);
1892
+ selection = result?.selection;
1893
+ } else if (selection === undefined) {
1894
+ selection = [];
1895
+ }
1896
+
1897
+ this.setOption("selection", validateArray(selection));
1898
+ checkOptionState.call(this);
1899
+
1900
+ try {
1901
+ this?.setFormValue(this.value);
1902
+ } catch (e) {
1903
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1904
+ }
1905
+
1906
+ fireCustomEvent(this, "monster-selected", {
1907
+ selection,
1908
+ });
1909
+
1910
+ return new Processing(() => {
1911
+ const CLASSNAME = "selected";
1912
+
1913
+ if (!this.shadowRoot) {
1914
+ throw new Error("no shadow-root is defined");
1915
+ }
1916
+
1917
+ const notSelected = this.shadowRoot.querySelectorAll(":not(:checked)");
1918
+
1919
+ if (notSelected) {
1920
+ notSelected.forEach((node) => {
1921
+ const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`);
1922
+ if (parent) {
1923
+ parent.classList.remove(CLASSNAME);
1924
+ }
1925
+ });
1926
+ }
1927
+
1928
+ const selected = this.shadowRoot.querySelectorAll(":checked");
1929
+ if (selected) {
1930
+ selected.forEach((node) => {
1931
+ const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`);
1932
+ if (parent) {
1933
+ parent.classList.add(CLASSNAME);
1934
+ }
1935
+ });
1936
+ }
1937
+ })
1938
+ .run()
1939
+ .catch((e) => {
1940
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
1941
+ });
1932
1942
  }
1933
1943
 
1934
1944
  /**
@@ -1939,131 +1949,134 @@ function setSelection(selection) {
1939
1949
  * @throws {TypeError} unsupported response
1940
1950
  */
1941
1951
  function fetchData(url) {
1942
-
1943
- if (!url) url = this.getOption("url");
1944
- if (!url) return Promise.resolve();
1945
-
1946
- const fetchOptions = this.getOption("fetch", {});
1947
-
1948
- setStatusOrRemoveBadges.call(this, "loading");
1949
- url = new Formatter({filter: this.getOption("filter.defaultValue")}).format(
1950
- url,
1951
- );
1952
-
1953
- const global = getGlobal();
1954
- return global
1955
- .fetch(url, fetchOptions)
1956
- .then((response) => {
1957
- const contentType = response.headers.get("content-type");
1958
- if (contentType && contentType.indexOf("application/json") !== -1) {
1959
- return response.text();
1960
- }
1961
-
1962
- throw new TypeError(`unsupported response ${contentType}`);
1963
- })
1964
- .then((text) => {
1965
- try {
1966
- return Promise.resolve(JSON.parse(String(text)));
1967
- } catch (e) {
1968
- throw new TypeError("the result cannot be parsed");
1969
- }
1970
- })
1971
- .catch((e) => {
1972
- throw e;
1973
- });
1952
+ if (!url) url = this.getOption("url");
1953
+ if (!url) return Promise.resolve();
1954
+
1955
+ const fetchOptions = this.getOption("fetch", {});
1956
+
1957
+ setStatusOrRemoveBadges.call(this, "loading");
1958
+ url = new Formatter({ filter: this.getOption("filter.defaultValue") }).format(
1959
+ url,
1960
+ );
1961
+
1962
+ const global = getGlobal();
1963
+ return global
1964
+ .fetch(url, fetchOptions)
1965
+ .then((response) => {
1966
+ const contentType = response.headers.get("content-type");
1967
+ if (contentType && contentType.indexOf("application/json") !== -1) {
1968
+ return response.text();
1969
+ }
1970
+
1971
+ throw new TypeError(`unsupported response ${contentType}`);
1972
+ })
1973
+ .then((text) => {
1974
+ try {
1975
+ return Promise.resolve(JSON.parse(String(text)));
1976
+ } catch (e) {
1977
+ throw new TypeError("the result cannot be parsed");
1978
+ }
1979
+ })
1980
+ .catch((e) => {
1981
+ throw e;
1982
+ });
1974
1983
  }
1975
1984
 
1976
1985
  /**
1977
1986
  * @private
1978
1987
  */
1979
1988
  function hide() {
1980
- this[popperElementSymbol].style.display = "none";
1981
- setStatusOrRemoveBadges.call(this, "status");
1982
- removeAttributeToken(this[controlElementSymbol], "class", "open");
1989
+ this[popperElementSymbol].style.display = "none";
1990
+ setStatusOrRemoveBadges.call(this, "status");
1991
+ removeAttributeToken(this[controlElementSymbol], "class", "open");
1983
1992
  }
1984
1993
 
1985
1994
  /**
1986
1995
  * @private
1987
1996
  */
1988
1997
  function show() {
1989
-
1990
- if (this.getOption("disabled", undefined) === true) {
1991
- return;
1992
- }
1993
-
1994
- if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
1995
- return;
1996
- }
1997
-
1998
- focusFilter.call(this);
1999
-
2000
- const lazyLoadFlag =
2001
- this.getOption("features.lazyLoad") && this[lazyLoadDoneSymbol] !== true;
2002
-
2003
- if (lazyLoadFlag === true) {
2004
- this[lazyLoadDoneSymbol] = true;
2005
- setStatusOrRemoveBadges.call(this, "loading");
2006
-
2007
- new Processing(200, () => {
2008
- this.fetch()
2009
- .then(() => {
2010
- setTimeout(() => {
2011
- let result;
2012
- if (this.hasAttribute("value")) {
2013
- result = setSelection.call(this, this.getAttribute("value"));
2014
- } else {
2015
- result = setSelection.call(this, []);
2016
- }
2017
-
2018
- result
2019
- .then(() => {
2020
- show.call(this);
2021
- })
2022
- .catch((e) => {
2023
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
2024
- });
2025
- }, 100);
2026
- })
2027
- .catch((e) => {
2028
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
2029
- setStatusOrRemoveBadges.call(this, "error");
2030
- });
2031
- })
2032
- .run()
2033
- .catch((e) => {
2034
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
2035
- });
2036
-
2037
- return;
2038
- }
2039
-
2040
- this[popperElementSymbol].style.visibility = "hidden";
2041
- this[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK;
2042
- setStatusOrRemoveBadges.call(this, "open");
2043
-
2044
- addAttributeToken(this[controlElementSymbol], "class", "open");
2045
-
2046
- new Processing(() => {
2047
- calcAndSetOptionsDimension.call(this);
2048
- focusFilter.call(this);
2049
- this[popperElementSymbol].style.removeProperty("visibility");
2050
- updatePopper.call(this);
2051
- })
2052
- .run()
2053
- .catch((e) => {
2054
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
2055
- });
1998
+ if (this.getOption("disabled", undefined) === true) {
1999
+ return;
2000
+ }
2001
+
2002
+ if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
2003
+ return;
2004
+ }
2005
+
2006
+ focusFilter.call(this);
2007
+
2008
+ const lazyLoadFlag =
2009
+ this.getOption("features.lazyLoad") && this[lazyLoadDoneSymbol] !== true;
2010
+
2011
+ if (lazyLoadFlag === true) {
2012
+ this[lazyLoadDoneSymbol] = true;
2013
+ setStatusOrRemoveBadges.call(this, "loading");
2014
+
2015
+ new Processing(200, () => {
2016
+ this.fetch()
2017
+ .then(() => {
2018
+ setTimeout(() => {
2019
+ let result;
2020
+ if (this.hasAttribute("value")) {
2021
+ result = setSelection.call(this, this.getAttribute("value"));
2022
+ } else {
2023
+ result = setSelection.call(this, []);
2024
+ }
2025
+
2026
+ result
2027
+ .then(() => {
2028
+ show.call(this);
2029
+ })
2030
+ .catch((e) => {
2031
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
2032
+ });
2033
+ }, 100);
2034
+ })
2035
+ .catch((e) => {
2036
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
2037
+ setStatusOrRemoveBadges.call(this, "error");
2038
+ });
2039
+ })
2040
+ .run()
2041
+ .catch((e) => {
2042
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
2043
+ });
2044
+
2045
+ return;
2046
+ }
2047
+
2048
+ const options = getOptionElements.call(this);
2049
+ if (options.length === 0) {
2050
+ return;
2051
+ }
2052
+
2053
+ this[popperElementSymbol].style.visibility = "hidden";
2054
+ this[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK;
2055
+ setStatusOrRemoveBadges.call(this, "open");
2056
+
2057
+ addAttributeToken(this[controlElementSymbol], "class", "open");
2058
+
2059
+ new Processing(() => {
2060
+ calcAndSetOptionsDimension.call(this);
2061
+ focusFilter.call(this);
2062
+ this[popperElementSymbol].style.removeProperty("visibility");
2063
+ updatePopper.call(this);
2064
+ })
2065
+ .run()
2066
+ .catch((e) => {
2067
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
2068
+ });
2056
2069
  }
2057
2070
 
2058
2071
  /**
2059
2072
  * @private
2060
2073
  */
2061
2074
  function toggle() {
2062
- if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
2063
- hide.call(this);
2064
- } else {
2065
- show.call(this);
2066
- }
2075
+ if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
2076
+ hide.call(this);
2077
+ } else {
2078
+ show.call(this);
2079
+ }
2067
2080
  }
2068
2081
 
2069
2082
  /**
@@ -2072,188 +2085,188 @@ function toggle() {
2072
2085
  * @fires Monster.Components.Form.event:monster-selection-cleared
2073
2086
  */
2074
2087
  function initEventHandler() {
2075
- const self = this;
2076
-
2077
- /**
2078
- * @param {Event} event
2079
- */
2080
- self[clearOptionEventHandler] = (event) => {
2081
- const element = findTargetElementFromEvent(
2082
- event,
2083
- ATTRIBUTE_ROLE,
2084
- "remove-badge",
2085
- );
2086
-
2087
- if (element instanceof HTMLElement) {
2088
- const badge = findClosestByAttribute(element, ATTRIBUTE_ROLE, "badge");
2089
- if (badge instanceof HTMLElement) {
2090
- const value = badge.getAttribute(`${ATTRIBUTE_PREFIX}value`);
2091
-
2092
- let selection = self.getOption("selection");
2093
- selection = selection.filter((b) => {
2094
- return value !== b.value;
2095
- });
2096
-
2097
- setSelection
2098
- .call(self, selection)
2099
- .then(() => {
2100
- fireCustomEvent(self, "monster-selection-removed", {
2101
- value,
2102
- });
2103
- })
2104
- .catch((e) => {
2105
- addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.message);
2106
- });
2107
- }
2108
- }
2109
- };
2110
-
2111
- /**
2112
- * @param {Event} event
2113
- */
2114
- self[closeEventHandler] = (event) => {
2115
- const path = event.composedPath();
2116
-
2117
- for (const [, element] of Object.entries(path)) {
2118
- if (element === self) {
2119
- return;
2120
- }
2121
- }
2122
- hide.call(self);
2123
- };
2124
-
2125
- /**
2126
- * @param {Event} event
2127
- */
2128
- self[inputEventHandler] = (event) => {
2129
- const path = event.composedPath();
2130
- const element = path?.[0];
2131
-
2132
- if (element instanceof HTMLElement) {
2133
- if (
2134
- element.hasAttribute(ATTRIBUTE_ROLE) &&
2135
- element.getAttribute(ATTRIBUTE_ROLE) === "option-control"
2136
- ) {
2137
- fireCustomEvent(self, "monster-change", {
2138
- type: event.type,
2139
- value: element.value,
2140
- checked: element.checked,
2141
- });
2142
- } else if (
2143
- element.hasAttribute(ATTRIBUTE_ROLE) &&
2144
- element.getAttribute(ATTRIBUTE_ROLE) === "filter"
2145
- ) {
2146
- }
2147
- }
2148
- };
2149
-
2150
- /**
2151
- * @param {Event} event
2152
- */
2153
- self[changeEventHandler] = (event) => {
2154
- gatherState.call(self);
2155
- fireCustomEvent(self, "monster-changed", event?.detail);
2156
- };
2157
-
2158
- self[keyEventHandler] = (event) => {
2159
- const path = event.composedPath();
2160
- const element = path.shift();
2161
-
2162
- let role;
2163
-
2164
- if (element instanceof HTMLElement) {
2165
- if (element.hasAttribute(ATTRIBUTE_ROLE)) {
2166
- role = element.getAttribute(ATTRIBUTE_ROLE);
2167
- } else if (element === this) {
2168
- show.call(this);
2169
- // focusFilter.call(self);
2170
- } else {
2171
- const e = element.closest(`[${ATTRIBUTE_ROLE}]`);
2172
- if (e instanceof HTMLElement && e.hasAttribute(ATTRIBUTE_ROLE)) {
2173
- role = e.getAttribute(ATTRIBUTE_ROLE);
2174
- }
2175
- }
2176
- } else {
2177
- return;
2178
- }
2179
-
2180
- switch (role) {
2181
- case "filter":
2182
- handleFilterKeyboardEvents.call(self, event);
2183
- break;
2184
- case "option-label":
2185
- case "option-control":
2186
- case "option":
2187
- handleOptionKeyboardEvents.call(self, event);
2188
- break;
2189
- case "control":
2190
- case "toggle":
2191
- handleToggleKeyboardEvents.call(self, event);
2192
- break;
2193
- }
2194
- };
2195
-
2196
- const types = self.getOption("toggleEventType", ["click"]);
2197
-
2198
- for (const [, type] of Object.entries(types)) {
2199
- self[controlElementSymbol]
2200
- .querySelector(`[${ATTRIBUTE_ROLE}="container"]`)
2201
- .addEventListener(type, function (event) {
2202
- const element = findTargetElementFromEvent(
2203
- event,
2204
- ATTRIBUTE_ROLE,
2205
- "remove-badge",
2206
- );
2207
- if (element instanceof HTMLElement) {
2208
- return;
2209
- }
2210
-
2211
- toggle.call(self);
2212
- });
2213
-
2214
- self[controlElementSymbol]
2215
- .querySelector(`[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`)
2216
- .addEventListener(type, function (event) {
2217
- if (self.getOption("disabled", undefined) === true) {
2218
- return;
2219
- }
2220
-
2221
- const path = event.composedPath();
2222
- const element = path?.[0];
2223
- if (element instanceof HTMLElement) {
2224
- const control = element.closest(
2225
- `[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`,
2226
- );
2227
- if (control instanceof HTMLElement) {
2228
- if (control.classList.contains("clear")) {
2229
- clearSelection.call(self);
2230
-
2231
- fireCustomEvent(self, "monster-selection-cleared", {});
2232
- } else {
2233
- const element = findTargetElementFromEvent(
2234
- event,
2235
- ATTRIBUTE_ROLE,
2236
- "remove-badge",
2237
- );
2238
- if (element instanceof HTMLElement) {
2239
- return;
2240
- }
2241
-
2242
- toggle.call(self);
2243
- }
2244
- }
2245
- }
2246
- });
2247
-
2248
- // badge, selection
2249
- self.addEventListener(type, self[clearOptionEventHandler]);
2250
- }
2251
-
2252
- self.addEventListener("monster-change", self[changeEventHandler]);
2253
- self.addEventListener("input", self[inputEventHandler]);
2254
- self.addEventListener("keydown", self[keyEventHandler]);
2255
-
2256
- return self;
2088
+ const self = this;
2089
+
2090
+ /**
2091
+ * @param {Event} event
2092
+ */
2093
+ self[clearOptionEventHandler] = (event) => {
2094
+ const element = findTargetElementFromEvent(
2095
+ event,
2096
+ ATTRIBUTE_ROLE,
2097
+ "remove-badge",
2098
+ );
2099
+
2100
+ if (element instanceof HTMLElement) {
2101
+ const badge = findClosestByAttribute(element, ATTRIBUTE_ROLE, "badge");
2102
+ if (badge instanceof HTMLElement) {
2103
+ const value = badge.getAttribute(`${ATTRIBUTE_PREFIX}value`);
2104
+
2105
+ let selection = self.getOption("selection");
2106
+ selection = selection.filter((b) => {
2107
+ return value !== b.value;
2108
+ });
2109
+
2110
+ setSelection
2111
+ .call(self, selection)
2112
+ .then(() => {
2113
+ fireCustomEvent(self, "monster-selection-removed", {
2114
+ value,
2115
+ });
2116
+ })
2117
+ .catch((e) => {
2118
+ addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.message);
2119
+ });
2120
+ }
2121
+ }
2122
+ };
2123
+
2124
+ /**
2125
+ * @param {Event} event
2126
+ */
2127
+ self[closeEventHandler] = (event) => {
2128
+ const path = event.composedPath();
2129
+
2130
+ for (const [, element] of Object.entries(path)) {
2131
+ if (element === self) {
2132
+ return;
2133
+ }
2134
+ }
2135
+ hide.call(self);
2136
+ };
2137
+
2138
+ /**
2139
+ * @param {Event} event
2140
+ */
2141
+ self[inputEventHandler] = (event) => {
2142
+ const path = event.composedPath();
2143
+ const element = path?.[0];
2144
+
2145
+ if (element instanceof HTMLElement) {
2146
+ if (
2147
+ element.hasAttribute(ATTRIBUTE_ROLE) &&
2148
+ element.getAttribute(ATTRIBUTE_ROLE) === "option-control"
2149
+ ) {
2150
+ fireCustomEvent(self, "monster-change", {
2151
+ type: event.type,
2152
+ value: element.value,
2153
+ checked: element.checked,
2154
+ });
2155
+ } else if (
2156
+ element.hasAttribute(ATTRIBUTE_ROLE) &&
2157
+ element.getAttribute(ATTRIBUTE_ROLE) === "filter"
2158
+ ) {
2159
+ }
2160
+ }
2161
+ };
2162
+
2163
+ /**
2164
+ * @param {Event} event
2165
+ */
2166
+ self[changeEventHandler] = (event) => {
2167
+ gatherState.call(self);
2168
+ fireCustomEvent(self, "monster-changed", event?.detail);
2169
+ };
2170
+
2171
+ self[keyEventHandler] = (event) => {
2172
+ const path = event.composedPath();
2173
+ const element = path.shift();
2174
+
2175
+ let role;
2176
+
2177
+ if (element instanceof HTMLElement) {
2178
+ if (element.hasAttribute(ATTRIBUTE_ROLE)) {
2179
+ role = element.getAttribute(ATTRIBUTE_ROLE);
2180
+ } else if (element === this) {
2181
+ show.call(this);
2182
+ // focusFilter.call(self);
2183
+ } else {
2184
+ const e = element.closest(`[${ATTRIBUTE_ROLE}]`);
2185
+ if (e instanceof HTMLElement && e.hasAttribute(ATTRIBUTE_ROLE)) {
2186
+ role = e.getAttribute(ATTRIBUTE_ROLE);
2187
+ }
2188
+ }
2189
+ } else {
2190
+ return;
2191
+ }
2192
+
2193
+ switch (role) {
2194
+ case "filter":
2195
+ handleFilterKeyboardEvents.call(self, event);
2196
+ break;
2197
+ case "option-label":
2198
+ case "option-control":
2199
+ case "option":
2200
+ handleOptionKeyboardEvents.call(self, event);
2201
+ break;
2202
+ case "control":
2203
+ case "toggle":
2204
+ handleToggleKeyboardEvents.call(self, event);
2205
+ break;
2206
+ }
2207
+ };
2208
+
2209
+ const types = self.getOption("toggleEventType", ["click"]);
2210
+
2211
+ for (const [, type] of Object.entries(types)) {
2212
+ self[controlElementSymbol]
2213
+ .querySelector(`[${ATTRIBUTE_ROLE}="container"]`)
2214
+ .addEventListener(type, function (event) {
2215
+ const element = findTargetElementFromEvent(
2216
+ event,
2217
+ ATTRIBUTE_ROLE,
2218
+ "remove-badge",
2219
+ );
2220
+ if (element instanceof HTMLElement) {
2221
+ return;
2222
+ }
2223
+
2224
+ toggle.call(self);
2225
+ });
2226
+
2227
+ self[controlElementSymbol]
2228
+ .querySelector(`[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`)
2229
+ .addEventListener(type, function (event) {
2230
+ if (self.getOption("disabled", undefined) === true) {
2231
+ return;
2232
+ }
2233
+
2234
+ const path = event.composedPath();
2235
+ const element = path?.[0];
2236
+ if (element instanceof HTMLElement) {
2237
+ const control = element.closest(
2238
+ `[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`,
2239
+ );
2240
+ if (control instanceof HTMLElement) {
2241
+ if (control.classList.contains("clear")) {
2242
+ clearSelection.call(self);
2243
+
2244
+ fireCustomEvent(self, "monster-selection-cleared", {});
2245
+ } else {
2246
+ const element = findTargetElementFromEvent(
2247
+ event,
2248
+ ATTRIBUTE_ROLE,
2249
+ "remove-badge",
2250
+ );
2251
+ if (element instanceof HTMLElement) {
2252
+ return;
2253
+ }
2254
+
2255
+ toggle.call(self);
2256
+ }
2257
+ }
2258
+ }
2259
+ });
2260
+
2261
+ // badge, selection
2262
+ self.addEventListener(type, self[clearOptionEventHandler]);
2263
+ }
2264
+
2265
+ self.addEventListener("monster-change", self[changeEventHandler]);
2266
+ self.addEventListener("input", self[inputEventHandler]);
2267
+ self.addEventListener("keydown", self[keyEventHandler]);
2268
+
2269
+ return self;
2257
2270
  }
2258
2271
 
2259
2272
  /**
@@ -2261,56 +2274,55 @@ function initEventHandler() {
2261
2274
  * @return {Select}
2262
2275
  */
2263
2276
  function setStatusOrRemoveBadges(suggestion) {
2264
-
2265
- setTimeout(() => {
2266
- const selection = this.getOption("selection");
2267
- const clearAllFlag =
2268
- isArray(selection) &&
2269
- selection.length > 0 &&
2270
- this.getOption("features.clearAll") === true;
2271
-
2272
- const current = this.getOption("classes.statusOrRemoveBadge");
2273
-
2274
- if (clearAllFlag) {
2275
- if (current !== "clear") {
2276
- this.setOption("classes.statusOrRemoveBadge", "clear");
2277
- }
2278
- return;
2279
- }
2280
-
2281
- if (suggestion === "loading") {
2282
- if (current !== "loading") {
2283
- this.setOption("classes.statusOrRemoveBadge", "loading");
2284
- }
2285
- return;
2286
- }
2287
-
2288
- if (this[controlElementSymbol].classList.contains("open")) {
2289
- if (current !== "open") {
2290
- this.setOption("classes.statusOrRemoveBadge", "open");
2291
- }
2292
- return;
2293
- }
2294
-
2295
- const options = this.getOption("options");
2296
- if (
2297
- options === undefined ||
2298
- options === null ||
2299
- (isArray(options) && options.length === 0)
2300
- ) {
2301
- if (current !== "empty") {
2302
- this.setOption("classes.statusOrRemoveBadge", "empty");
2303
- }
2304
- return;
2305
- }
2306
-
2307
- if (suggestion) {
2308
- if (current !== suggestion) {
2309
- this.setOption("classes.statusOrRemoveBadge", suggestion);
2310
- }
2311
- return;
2312
- }
2313
- }, 2);
2277
+ setTimeout(() => {
2278
+ const selection = this.getOption("selection");
2279
+ const clearAllFlag =
2280
+ isArray(selection) &&
2281
+ selection.length > 0 &&
2282
+ this.getOption("features.clearAll") === true;
2283
+
2284
+ const current = this.getOption("classes.statusOrRemoveBadge");
2285
+
2286
+ if (clearAllFlag) {
2287
+ if (current !== "clear") {
2288
+ this.setOption("classes.statusOrRemoveBadge", "clear");
2289
+ }
2290
+ return;
2291
+ }
2292
+
2293
+ if (suggestion === "loading") {
2294
+ if (current !== "loading") {
2295
+ this.setOption("classes.statusOrRemoveBadge", "loading");
2296
+ }
2297
+ return;
2298
+ }
2299
+
2300
+ if (this[controlElementSymbol].classList.contains("open")) {
2301
+ if (current !== "open") {
2302
+ this.setOption("classes.statusOrRemoveBadge", "open");
2303
+ }
2304
+ return;
2305
+ }
2306
+
2307
+ const options = this.getOption("options");
2308
+ if (
2309
+ options === undefined ||
2310
+ options === null ||
2311
+ (isArray(options) && options.length === 0)
2312
+ ) {
2313
+ if (current !== "empty") {
2314
+ this.setOption("classes.statusOrRemoveBadge", "empty");
2315
+ }
2316
+ return;
2317
+ }
2318
+
2319
+ if (suggestion) {
2320
+ if (current !== suggestion) {
2321
+ this.setOption("classes.statusOrRemoveBadge", suggestion);
2322
+ }
2323
+ return;
2324
+ }
2325
+ }, 2);
2314
2326
  }
2315
2327
 
2316
2328
  /**
@@ -2319,68 +2331,68 @@ function setStatusOrRemoveBadges(suggestion) {
2319
2331
  * @throws {Error} no shadow-root is defined
2320
2332
  */
2321
2333
  function initControlReferences() {
2322
- if (!this.shadowRoot) {
2323
- throw new Error("no shadow-root is defined");
2324
- }
2325
-
2326
- this[controlElementSymbol] = this.shadowRoot.querySelector(
2327
- `[${ATTRIBUTE_ROLE}=control]`,
2328
- );
2329
- this[selectionElementSymbol] = this.shadowRoot.querySelector(
2330
- `[${ATTRIBUTE_ROLE}=selection]`,
2331
- );
2332
- this[containerElementSymbol] = this.shadowRoot.querySelector(
2333
- `[${ATTRIBUTE_ROLE}=container]`,
2334
- );
2335
- this[popperElementSymbol] = this.shadowRoot.querySelector(
2336
- `[${ATTRIBUTE_ROLE}=popper]`,
2337
- );
2338
- this[inlineFilterElementSymbol] = this.shadowRoot.querySelector(
2339
- `[${ATTRIBUTE_ROLE}=filter][name="inline-filter"]`,
2340
- );
2341
- this[popperFilterElementSymbol] = this.shadowRoot.querySelector(
2342
- `[${ATTRIBUTE_ROLE}=filter][name="popper-filter"]`,
2343
- );
2344
- this[popperFilterContainerElementSymbol] =
2345
- this[popperFilterElementSymbol].parentElement;
2346
- this[optionsElementSymbol] = this.shadowRoot.querySelector(
2347
- `[${ATTRIBUTE_ROLE}=options]`,
2348
- );
2349
- this[noOptionsAvailableElementSymbol] = this.shadowRoot.querySelector(
2350
- `[${ATTRIBUTE_ROLE}="no-options"]`,
2351
- );
2352
- this[statusOrRemoveBadgesElementSymbol] = this.shadowRoot.querySelector(
2353
- `[${ATTRIBUTE_ROLE}=status-or-remove-badges]`,
2354
- );
2334
+ if (!this.shadowRoot) {
2335
+ throw new Error("no shadow-root is defined");
2336
+ }
2337
+
2338
+ this[controlElementSymbol] = this.shadowRoot.querySelector(
2339
+ `[${ATTRIBUTE_ROLE}=control]`,
2340
+ );
2341
+ this[selectionElementSymbol] = this.shadowRoot.querySelector(
2342
+ `[${ATTRIBUTE_ROLE}=selection]`,
2343
+ );
2344
+ this[containerElementSymbol] = this.shadowRoot.querySelector(
2345
+ `[${ATTRIBUTE_ROLE}=container]`,
2346
+ );
2347
+ this[popperElementSymbol] = this.shadowRoot.querySelector(
2348
+ `[${ATTRIBUTE_ROLE}=popper]`,
2349
+ );
2350
+ this[inlineFilterElementSymbol] = this.shadowRoot.querySelector(
2351
+ `[${ATTRIBUTE_ROLE}=filter][name="inline-filter"]`,
2352
+ );
2353
+ this[popperFilterElementSymbol] = this.shadowRoot.querySelector(
2354
+ `[${ATTRIBUTE_ROLE}=filter][name="popper-filter"]`,
2355
+ );
2356
+ this[popperFilterContainerElementSymbol] =
2357
+ this[popperFilterElementSymbol].parentElement;
2358
+ this[optionsElementSymbol] = this.shadowRoot.querySelector(
2359
+ `[${ATTRIBUTE_ROLE}=options]`,
2360
+ );
2361
+ this[noOptionsAvailableElementSymbol] = this.shadowRoot.querySelector(
2362
+ `[${ATTRIBUTE_ROLE}="no-options"]`,
2363
+ );
2364
+ this[statusOrRemoveBadgesElementSymbol] = this.shadowRoot.querySelector(
2365
+ `[${ATTRIBUTE_ROLE}=status-or-remove-badges]`,
2366
+ );
2355
2367
  }
2356
2368
 
2357
2369
  /**
2358
2370
  * @private
2359
2371
  */
2360
2372
  function updatePopper() {
2361
- if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) {
2362
- return;
2363
- }
2364
-
2365
- if (this.getOption("disabled", false) === true) {
2366
- return;
2367
- }
2368
-
2369
- new Processing(() => {
2370
- calcAndSetOptionsDimension.call(this);
2371
- positionPopper.call(
2372
- this,
2373
- this[controlElementSymbol],
2374
- this[popperElementSymbol],
2375
- this.getOption("popper", {}),
2376
- );
2377
- })
2378
- .run()
2379
- .catch((e) => {
2380
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
2381
- });
2382
-
2383
- return this;
2373
+ if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) {
2374
+ return;
2375
+ }
2376
+
2377
+ if (this.getOption("disabled", false) === true) {
2378
+ return;
2379
+ }
2380
+
2381
+ new Processing(() => {
2382
+ calcAndSetOptionsDimension.call(this);
2383
+ positionPopper.call(
2384
+ this,
2385
+ this[controlElementSymbol],
2386
+ this[popperElementSymbol],
2387
+ this.getOption("popper", {}),
2388
+ );
2389
+ })
2390
+ .run()
2391
+ .catch((e) => {
2392
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
2393
+ });
2394
+
2395
+ return this;
2384
2396
  }
2385
2397
 
2386
2398
  /**
@@ -2388,14 +2400,14 @@ function updatePopper() {
2388
2400
  * @return {string}
2389
2401
  */
2390
2402
  function getTemplate() {
2391
- // language=HTML
2392
- return `
2403
+ // language=HTML
2404
+ return `
2393
2405
  <template id="options">
2394
2406
  <div data-monster-role="option" tabindex="-1"
2395
2407
  data-monster-attributes="
2396
2408
  data-monster-filtered path:options.filtered,
2397
2409
  data-monster-visibility path:options.visibility">
2398
- <label part="option" role="option">
2410
+ <label part="option">
2399
2411
  <input data-monster-role="option-control"
2400
2412
  data-monster-attributes="
2401
2413
  type path:type,