@schukai/monster 3.55.6 → 3.56.1

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