@schukai/monster 3.102.5 → 3.103.0

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