@schukai/monster 3.101.3 → 3.102.0

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