@schukai/monster 3.56.1 → 3.57.0

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