@schukai/monster 3.57.0 → 3.58.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,