@schukai/monster 3.101.3 → 3.102.1

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