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