@schukai/monster 3.55.6 → 3.56.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/package.json +2 -2
  3. package/source/components/datatable/change-button.mjs +265 -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="