@schukai/monster 3.80.3 → 3.80.4

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