@schukai/monster 3.80.3 → 3.80.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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="