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