@schukai/monster 3.51.4 → 3.52.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.
- package/CHANGELOG.md +706 -0
- package/README.md +16 -13
- package/example/components/form/button.mjs +10 -0
- package/example/components/form/select.mjs +25 -0
- package/example/components/form/tree-select.mjs +27 -0
- package/example/components/host/host.mjs +0 -0
- package/example/components/notify/message.mjs +4 -0
- package/example/components/notify/notify.mjs +4 -0
- package/example/components/state/log.mjs +0 -0
- package/example/components/state/state.mjs +0 -0
- package/package.json +6 -2
- package/source/components/constants.mjs +132 -0
- package/source/components/datatable/columnbar.mjs +310 -0
- package/source/components/datatable/constants.mjs +121 -0
- package/source/components/datatable/dataset.mjs +219 -0
- package/source/components/datatable/datasource/dom.mjs +186 -0
- package/source/components/datatable/datasource/namespace.mjs +13 -0
- package/source/components/datatable/datasource/rest.mjs +400 -0
- package/source/components/datatable/datasource.mjs +102 -0
- package/source/components/datatable/datatable/header.mjs +268 -0
- package/source/components/datatable/datatable/namespace.mjs +13 -0
- package/source/components/datatable/datatable.mjs +789 -0
- package/source/components/datatable/embedded-pagination.mjs +113 -0
- package/source/components/datatable/filter/abstract-base.mjs +31 -0
- package/source/components/datatable/filter/date-range.mjs +1041 -0
- package/source/components/datatable/filter/input.mjs +175 -0
- package/source/components/datatable/filter/namespace.mjs +13 -0
- package/source/components/datatable/filter/range.mjs +671 -0
- package/source/components/datatable/filter/select.mjs +65 -0
- package/source/components/datatable/filter/settings.mjs +116 -0
- package/source/components/datatable/filter-button.mjs +98 -0
- package/source/components/datatable/filter.mjs +929 -0
- package/source/components/datatable/namespace.mjs +11 -0
- package/source/components/datatable/pagination.mjs +456 -0
- package/source/components/datatable/style/column-bar.pcss +123 -0
- package/source/components/datatable/style/dataset.pcss +13 -0
- package/source/components/datatable/style/datasource.pcss +16 -0
- package/source/components/datatable/style/datatable.pcss +239 -0
- package/source/components/datatable/style/embedded-pagination.pcss +101 -0
- package/source/components/datatable/style/filter-button.pcss +22 -0
- package/source/components/datatable/style/filter-controls-defaults.pcss +46 -0
- package/source/components/datatable/style/filter-date-range.pcss +9 -0
- package/source/components/datatable/style/filter-range.pcss +5 -0
- package/source/components/datatable/style/filter.pcss +156 -0
- package/source/components/datatable/style/pagination.pcss +59 -0
- package/source/components/datatable/style/select-filter.pcss +27 -0
- package/source/components/datatable/stylesheet/column-bar.mjs +33 -0
- package/source/components/datatable/stylesheet/dataset.mjs +33 -0
- package/source/components/datatable/stylesheet/datasource.mjs +33 -0
- package/source/components/datatable/stylesheet/datatable.mjs +33 -0
- package/source/components/datatable/stylesheet/embedded-pagination.mjs +33 -0
- package/source/components/datatable/stylesheet/filter-button.mjs +33 -0
- package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +33 -0
- package/source/components/datatable/stylesheet/filter-date-range.mjs +33 -0
- package/source/components/datatable/stylesheet/filter-range.mjs +33 -0
- package/source/components/datatable/stylesheet/filter.mjs +33 -0
- package/source/components/datatable/stylesheet/namespace.mjs +13 -0
- package/source/components/datatable/stylesheet/pagination.mjs +33 -0
- package/source/components/datatable/stylesheet/select-filter.mjs +33 -0
- package/source/components/datatable/util.mjs +60 -0
- package/source/components/form/action-button.mjs +262 -0
- package/source/components/form/api-button.mjs +515 -0
- package/source/components/form/button-bar.mjs +739 -0
- package/source/components/form/button.mjs +350 -0
- package/source/components/form/confirm-button.mjs +330 -0
- package/source/components/form/constants.mjs +111 -0
- package/source/components/form/context-help.mjs +123 -0
- package/source/components/form/events.mjs +84 -0
- package/source/components/form/form.mjs +601 -0
- package/source/components/form/message-state-button.mjs +396 -0
- package/source/components/form/namespace.mjs +13 -0
- package/source/components/form/popper-button.mjs +435 -0
- package/source/components/form/popper.mjs +487 -0
- package/source/components/form/reload.mjs +360 -0
- package/source/components/form/select.mjs +2314 -0
- package/source/components/form/shadow-reload.mjs +137 -0
- package/source/components/form/state-button.mjs +182 -0
- package/source/components/form/style/action-button.pcss +41 -0
- package/source/components/form/style/api-button.pcss +0 -0
- package/source/components/form/style/button-bar.pcss +51 -0
- package/source/components/form/style/button.pcss +8 -0
- package/source/components/form/style/confirm-button.pcss +17 -0
- package/source/components/form/style/context-help.pcss +16 -0
- package/source/components/form/style/form.pcss +10 -0
- package/source/components/form/style/message-state-button.pcss +10 -0
- package/source/components/form/style/popper-button.pcss +16 -0
- package/source/components/form/style/popper.pcss +8 -0
- package/source/components/form/style/select.pcss +265 -0
- package/source/components/form/style/state-button.pcss +116 -0
- package/source/components/form/style/tabs.pcss +170 -0
- package/source/components/form/style/tree-select.pcss +81 -0
- package/source/components/form/stylesheet/action-button.mjs +33 -0
- package/source/components/form/stylesheet/api-button.mjs +33 -0
- package/source/components/form/stylesheet/button-bar.mjs +33 -0
- package/source/components/form/stylesheet/button.mjs +33 -0
- package/source/components/form/stylesheet/confirm-button.mjs +33 -0
- package/source/components/form/stylesheet/context-help.mjs +33 -0
- package/source/components/form/stylesheet/form.mjs +33 -0
- package/source/components/form/stylesheet/message-state-button.mjs +33 -0
- package/source/components/form/stylesheet/namespace.mjs +13 -0
- package/source/components/form/stylesheet/popper-button.mjs +33 -0
- package/source/components/form/stylesheet/popper.mjs +33 -0
- package/source/components/form/stylesheet/select.mjs +33 -0
- package/source/components/form/stylesheet/state-button.mjs +33 -0
- package/source/components/form/stylesheet/tabs.mjs +33 -0
- package/source/components/form/stylesheet/tree-select.mjs +33 -0
- package/source/components/form/tabs.mjs +1011 -0
- package/source/components/form/template.mjs +373 -0
- package/source/components/form/tree-select.mjs +527 -0
- package/source/components/form/types/namespace.mjs +13 -0
- package/source/components/form/types/state.mjs +93 -0
- package/source/components/form/util/fetch.mjs +133 -0
- package/source/components/form/util/floating-ui.mjs +245 -0
- package/source/components/form/util/namespace.mjs +13 -0
- package/source/components/form/util/popper.mjs +49 -0
- package/source/components/host/call-button.mjs +236 -0
- package/source/components/host/collapse.mjs +526 -0
- package/source/components/host/config-manager.mjs +304 -0
- package/source/components/host/constants.mjs +18 -0
- package/source/components/host/details.mjs +268 -0
- package/source/components/host/events.mjs +131 -0
- package/source/components/host/host.mjs +420 -0
- package/source/components/host/namespace.mjs +13 -0
- package/source/components/host/overlay.mjs +339 -0
- package/source/components/host/style/call-button.pcss +36 -0
- package/source/components/host/style/collapse.pcss +67 -0
- package/source/components/host/style/config-manager.pcss +5 -0
- package/source/components/host/style/details.pcss +68 -0
- package/source/components/host/style/host.pcss +43 -0
- package/source/components/host/style/overlay.pcss +73 -0
- package/source/components/host/style/toggle-button.pcss +36 -0
- package/source/components/host/style/viewer.pcss +13 -0
- package/source/components/host/stylesheet/call-button.mjs +33 -0
- package/source/components/host/stylesheet/collapse.mjs +33 -0
- package/source/components/host/stylesheet/config-manager.mjs +33 -0
- package/source/components/host/stylesheet/details.mjs +33 -0
- package/source/components/host/stylesheet/host.mjs +33 -0
- package/source/components/host/stylesheet/namespace.mjs +13 -0
- package/source/components/host/stylesheet/overlay.mjs +33 -0
- package/source/components/host/stylesheet/toggle-button.mjs +33 -0
- package/source/components/host/stylesheet/viewer.mjs +33 -0
- package/source/components/host/toggle-button.mjs +88 -0
- package/source/components/host/util.mjs +23 -0
- package/source/components/host/viewer.mjs +309 -0
- package/source/components/namespace.mjs +14 -0
- package/source/components/notify/constants.mjs +15 -0
- package/source/components/notify/events.mjs +15 -0
- package/source/components/notify/message.mjs +374 -0
- package/source/components/notify/namespace.mjs +15 -0
- package/source/components/notify/notify.mjs +236 -0
- package/source/components/notify/style/message.pcss +57 -0
- package/source/components/notify/style/notify.pcss +118 -0
- package/source/components/notify/stylesheet/message.mjs +33 -0
- package/source/components/notify/stylesheet/namespace.mjs +15 -0
- package/source/components/notify/stylesheet/notify.mjs +33 -0
- package/source/components/state/log/entry.mjs +126 -0
- package/source/components/state/log/namespace.mjs +13 -0
- package/source/components/state/log.mjs +275 -0
- package/source/components/state/namespace.mjs +13 -0
- package/source/components/state/state.mjs +131 -0
- package/source/components/state/style/log.pcss +111 -0
- package/source/components/state/style/state.pcss +113 -0
- package/source/components/state/stylesheet/log.mjs +33 -0
- package/source/components/state/stylesheet/state.mjs +33 -0
- package/source/components/style/badge.pcss +92 -0
- package/source/components/style/border.pcss +77 -0
- package/source/components/style/button.pcss +105 -0
- package/source/components/style/card.pcss +108 -0
- package/source/components/style/color.pcss +257 -0
- package/source/components/style/common.pcss +103 -0
- package/source/components/style/control.pcss +11 -0
- package/source/components/style/data-grid.pcss +43 -0
- package/source/components/style/display.pcss +42 -0
- package/source/components/style/floating-ui.pcss +33 -0
- package/source/components/style/form.pcss +5 -0
- package/source/components/style/host.pcss +15 -0
- package/source/components/style/link.pcss +63 -0
- package/source/components/style/mixin/badge.pcss +18 -0
- package/source/components/style/mixin/button.pcss +54 -0
- package/source/components/style/mixin/form.pcss +247 -0
- package/source/components/style/mixin/hover.pcss +8 -0
- package/source/components/style/mixin/media.pcss +107 -0
- package/source/components/style/mixin/property.pcss +288 -0
- package/source/components/style/mixin/skeleton.pcss +26 -0
- package/source/components/style/mixin/spinner.pcss +24 -0
- package/source/components/style/mixin/typography.pcss +52 -0
- package/source/components/style/normalize.pcss +14 -0
- package/source/components/style/popper.pcss +78 -0
- package/source/components/style/property.pcss +17 -0
- package/source/components/style/ripple.pcss +14 -0
- package/source/components/style/skeleton.pcss +28 -0
- package/source/components/style/space.pcss +47 -0
- package/source/components/style/spinner.pcss +6 -0
- package/source/components/style/table.pcss +46 -0
- package/source/components/style/theme.pcss +119 -0
- package/source/components/style/typography.pcss +131 -0
- package/source/components/stylesheet/badge.mjs +33 -0
- package/source/components/stylesheet/border.mjs +33 -0
- package/source/components/stylesheet/button.mjs +33 -0
- package/source/components/stylesheet/card.mjs +33 -0
- package/source/components/stylesheet/color.mjs +33 -0
- package/source/components/stylesheet/common.mjs +33 -0
- package/source/components/stylesheet/control.mjs +33 -0
- package/source/components/stylesheet/data-grid.mjs +33 -0
- package/source/components/stylesheet/display.mjs +33 -0
- package/source/components/stylesheet/floating-ui.mjs +33 -0
- package/source/components/stylesheet/form.mjs +33 -0
- package/source/components/stylesheet/host.mjs +33 -0
- package/source/components/stylesheet/link.mjs +33 -0
- package/source/components/stylesheet/namespace.mjs +13 -0
- package/source/components/stylesheet/normalize.mjs +33 -0
- package/source/components/stylesheet/popper.mjs +33 -0
- package/source/components/stylesheet/property.mjs +33 -0
- package/source/components/stylesheet/ripple.mjs +33 -0
- package/source/components/stylesheet/skeleton.mjs +33 -0
- package/source/components/stylesheet/space.mjs +33 -0
- package/source/components/stylesheet/spinner.mjs +33 -0
- package/source/components/stylesheet/table.mjs +33 -0
- package/source/components/stylesheet/theme.mjs +33 -0
- package/source/components/stylesheet/tree-menu.mjs +33 -0
- package/source/components/stylesheet/typography.mjs +33 -0
- package/source/components/tree-menu/namespace.mjs +13 -0
- package/source/components/tree-menu/style/tree-menu.pcss +107 -0
- package/source/components/tree-menu/stylesheet/namespace.mjs +13 -0
- package/source/components/tree-menu/stylesheet/tree-menu.mjs +33 -0
- package/source/components/tree-menu/tree-menu.mjs +660 -0
- package/source/constraints/abstract.mjs +17 -24
- package/source/constraints/abstractoperator.mjs +27 -22
- package/source/constraints/andoperator.mjs +20 -17
- package/source/constraints/invalid.mjs +17 -17
- package/source/constraints/isarray.mjs +20 -20
- package/source/constraints/isobject.mjs +20 -20
- package/source/constraints/oroperator.mjs +45 -45
- package/source/constraints/valid.mjs +17 -17
- package/source/data/buildmap.mjs +108 -103
- package/source/data/buildtree.mjs +59 -57
- package/source/data/datasource/dom.mjs +80 -84
- package/source/data/datasource/namespace.mjs +1 -1
- package/source/data/datasource/server/restapi/data-fetch-error.mjs +27 -25
- package/source/data/datasource/server/restapi/writeerror.mjs +34 -32
- package/source/data/datasource/server/restapi.mjs +176 -177
- package/source/data/datasource/server/webconnect.mjs +150 -156
- package/source/data/datasource/server.mjs +58 -59
- package/source/data/datasource/storage/localstorage.mjs +25 -24
- package/source/data/datasource/storage/sessionstorage.mjs +28 -25
- package/source/data/datasource/storage.mjs +74 -73
- package/source/data/datasource.mjs +176 -167
- package/source/data/diff.mjs +98 -97
- package/source/data/extend.mjs +42 -42
- package/source/data/pathfinder.mjs +301 -288
- package/source/data/pipe.mjs +36 -36
- package/source/data/transformer.mjs +742 -726
- package/source/dom/assembler.mjs +44 -44
- package/source/dom/attributes.mjs +142 -122
- package/source/dom/constants.mjs +62 -58
- package/source/dom/customcontrol.mjs +299 -299
- package/source/dom/customelement.mjs +843 -806
- package/source/dom/dimension.mjs +56 -46
- package/source/dom/events.mjs +74 -69
- package/source/dom/focusmanager.mjs +175 -175
- package/source/dom/locale.mjs +28 -28
- package/source/dom/ready.mjs +13 -13
- package/source/dom/resource/data.mjs +117 -111
- package/source/dom/resource/link/stylesheet.mjs +16 -16
- package/source/dom/resource/link.mjs +94 -96
- package/source/dom/resource/script.mjs +72 -74
- package/source/dom/resource.mjs +174 -172
- package/source/dom/resourcemanager.mjs +152 -156
- package/source/dom/slotted.mjs +78 -80
- package/source/dom/template.mjs +126 -112
- package/source/dom/theme.mjs +35 -35
- package/source/dom/updater.mjs +673 -651
- package/source/dom/util/extract-keys.mjs +34 -22
- package/source/dom/util/init-options-from-attributes.mjs +46 -38
- package/source/dom/util/namespace.mjs +13 -0
- package/source/dom/util/set-option-from-attribute.mjs +35 -29
- package/source/dom/util.mjs +112 -81
- package/source/dom/worker/factory.mjs +83 -83
- package/source/i18n/formatter.mjs +75 -73
- package/source/i18n/locale.mjs +146 -144
- package/source/i18n/provider.mjs +70 -64
- package/source/i18n/providers/embed.mjs +136 -127
- package/source/i18n/providers/fetch.mjs +84 -76
- package/source/i18n/translations.mjs +205 -195
- package/source/logging/handler/console.mjs +36 -36
- package/source/logging/handler.mjs +140 -140
- package/source/logging/logentry.mjs +25 -25
- package/source/logging/logger.mjs +177 -175
- package/source/math/random.mjs +63 -59
- package/source/monster.mjs +226 -217
- package/source/net/webconnect/message.mjs +31 -31
- package/source/net/webconnect.mjs +278 -271
- package/source/text/bracketed-key-value-hash.mjs +182 -179
- package/source/text/formatter.mjs +235 -210
- package/source/text/generate-range-comparison-expression.mjs +56 -34
- package/source/text/namespace.mjs +1 -1
- package/source/types/base.mjs +69 -61
- package/source/types/basewithoptions.mjs +46 -46
- package/source/types/binary.mjs +20 -20
- package/source/types/dataurl.mjs +96 -90
- package/source/types/global.mjs +45 -39
- package/source/types/id.mjs +25 -25
- package/source/types/internal.mjs +115 -114
- package/source/types/is.mjs +56 -40
- package/source/types/mediatype.mjs +119 -119
- package/source/types/namespace.mjs +1 -1
- package/source/types/node.mjs +160 -150
- package/source/types/nodelist.mjs +94 -96
- package/source/types/noderecursiveiterator.mjs +50 -50
- package/source/types/observablequeue.mjs +73 -73
- package/source/types/observer.mjs +104 -104
- package/source/types/observerlist.mjs +66 -66
- package/source/types/proxyobserver.mjs +210 -210
- package/source/types/queue.mjs +63 -63
- package/source/types/randomid.mjs +13 -13
- package/source/types/regex.mjs +3 -1
- package/source/types/stack.mjs +64 -64
- package/source/types/tokenlist.mjs +206 -205
- package/source/types/typeof.mjs +12 -10
- package/source/types/uniquequeue.mjs +48 -48
- package/source/types/uuid.mjs +32 -32
- package/source/types/validate.mjs +67 -67
- package/source/types/version.mjs +115 -105
- package/source/util/clone.mjs +103 -91
- package/source/util/comparator.mjs +97 -97
- package/source/util/deadmansswitch.mjs +40 -44
- package/source/util/freeze.mjs +10 -9
- package/source/util/namespace.mjs +1 -1
- package/source/util/processing.mjs +104 -105
- package/source/util/runtime.mjs +56 -44
- package/source/util/trimspaces.mjs +24 -24
- package/test/cases/components/form/button.mjs +122 -0
- package/test/cases/components/form/confirm-button.mjs +127 -0
- package/test/cases/components/form/form.mjs +317 -0
- package/test/cases/components/form/reload.mjs +188 -0
- package/test/cases/components/form/select.mjs +229 -0
- package/test/cases/components/form/state-button.mjs +130 -0
- package/test/cases/components/form/tabs.mjs +98 -0
- package/test/cases/components/form/template.mjs +189 -0
- package/test/cases/components/form/tree-select.mjs +216 -0
- package/test/cases/components/host/details.mjs +68 -0
- package/test/cases/components/host/host.mjs +70 -0
- package/test/cases/components/host/overlay.mjs +60 -0
- package/test/cases/components/host/util.mjs +79 -0
- package/test/cases/components/notify/message.mjs +39 -0
- package/test/cases/components/notify/notify.mjs +89 -0
- package/test/cases/constraint/abstractoperator.mjs +2 -2
- package/test/cases/constraint/andoperator.mjs +3 -3
- package/test/cases/constraint/invalid.mjs +1 -1
- package/test/cases/constraint/isarray.mjs +1 -1
- package/test/cases/constraint/isobject.mjs +1 -1
- package/test/cases/constraint/oroperator.mjs +3 -3
- package/test/cases/constraint/valid.mjs +1 -1
- package/test/cases/data/buildmap.mjs +1 -1
- package/test/cases/data/buildtree.mjs +2 -2
- package/test/cases/data/datasource/dom.mjs +1 -1
- package/test/cases/data/datasource/server/restapi.mjs +2 -2
- package/test/cases/data/datasource/server/websocket.mjs +1 -1
- package/test/cases/data/datasource/server.mjs +1 -1
- package/test/cases/data/datasource/storage/localstorage.mjs +1 -1
- package/test/cases/data/datasource/storage/sessionstorage.mjs +1 -1
- package/test/cases/data/datasource.mjs +1 -1
- package/test/cases/data/diff.mjs +2 -2
- package/test/cases/data/extend.mjs +1 -1
- package/test/cases/data/pathfinder.mjs +1 -1
- package/test/cases/data/pipe.mjs +2 -2
- package/test/cases/data/transformer.mjs +3 -4
- package/test/cases/dom/assembler.mjs +1 -1
- package/test/cases/dom/attributes.mjs +1 -1
- package/test/cases/dom/customcontrol.mjs +8 -7
- package/test/cases/dom/customelement-initfromscripthost.mjs +6 -6
- package/test/cases/dom/customelement.mjs +7 -7
- package/test/cases/dom/dimension.mjs +4 -4
- package/test/cases/dom/events.mjs +1 -1
- package/test/cases/dom/find.mjs +1 -1
- package/test/cases/dom/focusmanager.mjs +1 -1
- package/test/cases/dom/locale.mjs +2 -2
- package/test/cases/dom/ready.mjs +1 -1
- package/test/cases/dom/resource/data.mjs +3 -3
- package/test/cases/dom/resource/link/stylesheet.mjs +3 -3
- package/test/cases/dom/resource/link.mjs +3 -3
- package/test/cases/dom/resource/script.mjs +3 -3
- package/test/cases/dom/resource.mjs +1 -1
- package/test/cases/dom/resourcemanager.mjs +1 -1
- package/test/cases/dom/slotted-nodes.mjs +1 -1
- package/test/cases/dom/template.mjs +2 -2
- package/test/cases/dom/theme.mjs +2 -2
- package/test/cases/dom/updater.mjs +4 -4
- package/test/cases/dom/util/extract-keys.mjs +1 -1
- package/test/cases/dom/util/init-options-from-attributes.mjs +1 -1
- package/test/cases/dom/util.mjs +2 -2
- package/test/cases/dom/worker/factory.mjs +2 -2
- package/test/cases/i18n/formatter.mjs +2 -2
- package/test/cases/i18n/locale.mjs +1 -1
- package/test/cases/i18n/provider.mjs +4 -4
- package/test/cases/i18n/providers/embed.mjs +3 -3
- package/test/cases/i18n/providers/fetch.mjs +3 -3
- package/test/cases/i18n/translations.mjs +3 -3
- package/test/cases/logging/handler/console.mjs +3 -3
- package/test/cases/logging/handler.mjs +3 -3
- package/test/cases/logging/logentry.mjs +1 -1
- package/test/cases/logging/logger.mjs +1 -1
- package/test/cases/math/random.mjs +1 -2
- package/test/cases/monster.mjs +2 -2
- package/test/cases/net/webconnect/message.mjs +1 -2
- package/test/cases/net/webconnect.mjs +3 -3
- package/test/cases/text/bracketed-key-value-hash.mjs +1 -1
- package/test/cases/text/formatter.mjs +1 -1
- package/test/cases/text/util.mjs +1 -1
- package/test/cases/types/base.mjs +2 -2
- package/test/cases/types/basewithoptions.mjs +1 -1
- package/test/cases/types/binary.mjs +1 -1
- package/test/cases/types/dataurl.mjs +1 -1
- package/test/cases/types/global.mjs +1 -1
- package/test/cases/types/id.mjs +1 -1
- package/test/cases/types/internal.mjs +2 -2
- package/test/cases/types/is.mjs +2 -2
- package/test/cases/types/mediatype.mjs +1 -1
- package/test/cases/types/node.mjs +4 -4
- package/test/cases/types/nodelist.mjs +2 -2
- package/test/cases/types/noderecursiveiterator.mjs +3 -3
- package/test/cases/types/observablequeue.mjs +2 -2
- package/test/cases/types/observer.mjs +1 -1
- package/test/cases/types/observerlist.mjs +2 -2
- package/test/cases/types/proxyobserver.mjs +4 -4
- package/test/cases/types/queue.mjs +1 -1
- package/test/cases/types/randomid.mjs +1 -1
- package/test/cases/types/regex.mjs +1 -1
- package/test/cases/types/stack.mjs +1 -1
- package/test/cases/types/tokenlist.mjs +1 -1
- package/test/cases/types/typeof.mjs +2 -2
- package/test/cases/types/uniquequeue.mjs +1 -1
- package/test/cases/types/uuid.mjs +1 -1
- package/test/cases/types/validate.mjs +3 -3
- package/test/cases/types/version.mjs +1 -1
- package/test/cases/util/clone.mjs +1 -1
- package/test/cases/util/comparator.mjs +1 -1
- package/test/cases/util/deadmansswitch.mjs +1 -1
- package/test/cases/util/freeze.mjs +1 -1
- package/test/cases/util/processing.mjs +1 -1
- package/test/cases/util/trimspaces.mjs +1 -1
- package/test/util/chai-dom.mjs +2 -2
- package/test/util/intersection-mock.mjs +69 -0
- package/test/util/jsdom.mjs +43 -27
- package/test/util/localstorage.mjs +1 -0
- package/test/util/resize-observer.mjs +29 -0
- package/test/util/websocket.mjs +5 -2
- package/test/web/import.js +92 -73
- package/test/web/test.html +28 -5
- package/test/web/tests.js +29430 -15209
- package/CHANGELOG +0 -438
|
@@ -0,0 +1,2314 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright schukai GmbH and contributors 2023. All Rights Reserved.
|
|
3
|
+
* Node module: @schukai/monster
|
|
4
|
+
* This file is licensed under the AGPLv3 License.
|
|
5
|
+
* License text available at https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
6
|
+
*/
|
|
7
|
+
import { instanceSymbol } from "../../constants.mjs";
|
|
8
|
+
import { internalSymbol } from "../../constants.mjs";
|
|
9
|
+
import { buildMap } from "../../data/buildmap.mjs";
|
|
10
|
+
import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
|
|
11
|
+
import { positionPopper } from "./util/floating-ui.mjs";
|
|
12
|
+
import {
|
|
13
|
+
addAttributeToken,
|
|
14
|
+
findClosestByAttribute,
|
|
15
|
+
removeAttributeToken,
|
|
16
|
+
} from "../../dom/attributes.mjs";
|
|
17
|
+
import {
|
|
18
|
+
ATTRIBUTE_ERRORMESSAGE,
|
|
19
|
+
ATTRIBUTE_PREFIX,
|
|
20
|
+
ATTRIBUTE_ROLE,
|
|
21
|
+
} from "../../dom/constants.mjs";
|
|
22
|
+
import { CustomControl } from "../../dom/customcontrol.mjs";
|
|
23
|
+
import {
|
|
24
|
+
assembleMethodSymbol,
|
|
25
|
+
getSlottedElements,
|
|
26
|
+
registerCustomElement,
|
|
27
|
+
} from "../../dom/customelement.mjs";
|
|
28
|
+
import {
|
|
29
|
+
findTargetElementFromEvent,
|
|
30
|
+
fireCustomEvent,
|
|
31
|
+
fireEvent,
|
|
32
|
+
} from "../../dom/events.mjs";
|
|
33
|
+
import { getDocument } from "../../dom/util.mjs";
|
|
34
|
+
import { Formatter } from "../../text/formatter.mjs";
|
|
35
|
+
import { getGlobal } from "../../types/global.mjs";
|
|
36
|
+
import { ID } from "../../types/id.mjs";
|
|
37
|
+
import {
|
|
38
|
+
isArray,
|
|
39
|
+
isFunction,
|
|
40
|
+
isInteger,
|
|
41
|
+
isIterable,
|
|
42
|
+
isObject,
|
|
43
|
+
isPrimitive,
|
|
44
|
+
isString,
|
|
45
|
+
} from "../../types/is.mjs";
|
|
46
|
+
import { Observer } from "../../types/observer.mjs";
|
|
47
|
+
import { ProxyObserver } from "../../types/proxyobserver.mjs";
|
|
48
|
+
import { validateArray, validateString } from "../../types/validate.mjs";
|
|
49
|
+
import { Processing } from "../../util/processing.mjs";
|
|
50
|
+
import { STYLE_DISPLAY_MODE_BLOCK } from "./constants.mjs";
|
|
51
|
+
import { SelectStyleSheet } from "./stylesheet/select.mjs";
|
|
52
|
+
import {
|
|
53
|
+
getDocumentTranslations,
|
|
54
|
+
Translations,
|
|
55
|
+
} from "../../i18n/translations.mjs";
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
Select,
|
|
59
|
+
popperElementSymbol,
|
|
60
|
+
getSummaryTemplate,
|
|
61
|
+
getSelectionTemplate,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @private
|
|
66
|
+
* @type {string}
|
|
67
|
+
*/
|
|
68
|
+
const noOptionsAvailableMessage = "No options available.";
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @private
|
|
72
|
+
* @type {symbol}
|
|
73
|
+
*/
|
|
74
|
+
const timerCallbackSymbol = Symbol("timerCallback");
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* local symbol
|
|
78
|
+
* @private
|
|
79
|
+
* @type {symbol}
|
|
80
|
+
*/
|
|
81
|
+
const closeEventHandler = Symbol("closeEventHandler");
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* local symbol
|
|
85
|
+
* @private
|
|
86
|
+
* @type {symbol}
|
|
87
|
+
*/
|
|
88
|
+
const clearOptionEventHandler = Symbol("clearOptionEventHandler");
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* local symbol
|
|
92
|
+
* @private
|
|
93
|
+
* @type {symbol}
|
|
94
|
+
*/
|
|
95
|
+
const resizeObserverSymbol = Symbol("resizeObserver");
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* local symbol
|
|
99
|
+
* @private
|
|
100
|
+
* @type {symbol}
|
|
101
|
+
*/
|
|
102
|
+
const keyEventHandler = Symbol("keyEventHandler");
|
|
103
|
+
/**
|
|
104
|
+
* local symbol
|
|
105
|
+
* @private
|
|
106
|
+
* @type {symbol}
|
|
107
|
+
*/
|
|
108
|
+
const inputEventHandler = Symbol("inputEventHandler");
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* local symbol
|
|
112
|
+
* @private
|
|
113
|
+
* @type {symbol}
|
|
114
|
+
*/
|
|
115
|
+
const changeEventHandler = Symbol("changeEventHandler");
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* local symbol
|
|
119
|
+
* @private
|
|
120
|
+
* @type {symbol}
|
|
121
|
+
*/
|
|
122
|
+
const controlElementSymbol = Symbol("controlElement");
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* local symbol
|
|
126
|
+
* @private
|
|
127
|
+
* @type {symbol}
|
|
128
|
+
*/
|
|
129
|
+
const selectionElementSymbol = Symbol("selectionElement");
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* local symbol
|
|
133
|
+
* @private
|
|
134
|
+
* @type {symbol}
|
|
135
|
+
*/
|
|
136
|
+
const containerElementSymbol = Symbol("containerElement");
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* local symbol
|
|
140
|
+
* @private
|
|
141
|
+
* @type {symbol}
|
|
142
|
+
*/
|
|
143
|
+
const popperElementSymbol = Symbol("popperElement");
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* local symbol
|
|
147
|
+
* @private
|
|
148
|
+
* @type {symbol}
|
|
149
|
+
*/
|
|
150
|
+
const inlineFilterElementSymbol = Symbol("inlineFilterElement");
|
|
151
|
+
/**
|
|
152
|
+
* local symbol
|
|
153
|
+
* @private
|
|
154
|
+
* @type {symbol}
|
|
155
|
+
*/
|
|
156
|
+
const popperFilterElementSymbol = Symbol("popperFilterElement");
|
|
157
|
+
/**
|
|
158
|
+
* local symbol
|
|
159
|
+
* @private
|
|
160
|
+
* @type {symbol}
|
|
161
|
+
*/
|
|
162
|
+
const popperFilterContainerElementSymbol = Symbol(
|
|
163
|
+
"popperFilterContainerElement",
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* local symbol
|
|
168
|
+
* @private
|
|
169
|
+
* @type {symbol}
|
|
170
|
+
*/
|
|
171
|
+
const optionsElementSymbol = Symbol("optionsElement");
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* local symbol
|
|
175
|
+
* @private
|
|
176
|
+
* @type {symbol}
|
|
177
|
+
*/
|
|
178
|
+
const noOptionsAvailableElementSymbol = Symbol("noOptionsAvailableElement");
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* local symbol
|
|
182
|
+
* @private
|
|
183
|
+
* @type {symbol}
|
|
184
|
+
*/
|
|
185
|
+
const statusOrRemoveBadgesElementSymbol = Symbol("statusOrRemoveBadgesElement");
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* @private
|
|
189
|
+
* @type {symbol}
|
|
190
|
+
*/
|
|
191
|
+
const areOptionsAvailableAndInitSymbol = Symbol("@@areOptionsAvailableAndInit");
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @private
|
|
195
|
+
* @type {number}
|
|
196
|
+
*/
|
|
197
|
+
const FOCUS_DIRECTION_UP = 1;
|
|
198
|
+
/**
|
|
199
|
+
* @private
|
|
200
|
+
* @type {number}
|
|
201
|
+
*/
|
|
202
|
+
const FOCUS_DIRECTION_DOWN = 2;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @private
|
|
206
|
+
* @type {string}
|
|
207
|
+
*/
|
|
208
|
+
const FILTER_MODE_REMOTE = "remote";
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @private
|
|
212
|
+
* @type {string}
|
|
213
|
+
*/
|
|
214
|
+
const FILTER_MODE_OPTIONS = "options";
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* @private
|
|
218
|
+
* @type {string}
|
|
219
|
+
*/
|
|
220
|
+
const FILTER_MODE_DISABLED = "disabled";
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @private
|
|
224
|
+
* @type {string}
|
|
225
|
+
*/
|
|
226
|
+
const FILTER_POSITION_POPPER = "popper";
|
|
227
|
+
/**
|
|
228
|
+
* @private
|
|
229
|
+
* @type {string}
|
|
230
|
+
*/
|
|
231
|
+
const FILTER_POSITION_INLINE = "inline";
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @typedef {Object} Selection
|
|
235
|
+
* @property {*} value
|
|
236
|
+
* @property {String} label
|
|
237
|
+
* @memberOf Monster.Components.Form
|
|
238
|
+
* @since 1.2.0
|
|
239
|
+
*/
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* This CustomControl creates a select element with a variety of options.
|
|
243
|
+
* It supports filtering, local and remote, multiple selection and has a
|
|
244
|
+
* template system for displaying the options.
|
|
245
|
+
*
|
|
246
|
+
* <img src="./images/select.png">
|
|
247
|
+
*
|
|
248
|
+
* Dependencies: the system uses functions of the [monsterjs](https://monsterjs.org/) library
|
|
249
|
+
* as well as [pooperjs](https://popper.js.org/docs/v2/).
|
|
250
|
+
*
|
|
251
|
+
* You can create this control either by specifying the HTML tag `<monster-select />` directly in the HTML or using
|
|
252
|
+
* Javascript via the `document.createElement('monster-select');` method.
|
|
253
|
+
*
|
|
254
|
+
* ```html
|
|
255
|
+
* <monster-select></monster-select>
|
|
256
|
+
* ```
|
|
257
|
+
*
|
|
258
|
+
* Or you can create this CustomControl directly in Javascript:
|
|
259
|
+
*
|
|
260
|
+
* ```js
|
|
261
|
+
* import {Select} from '@schukai/component-form/source/select.js';
|
|
262
|
+
* document.createElement('monster-select');
|
|
263
|
+
* ```
|
|
264
|
+
*
|
|
265
|
+
* ## Events
|
|
266
|
+
*
|
|
267
|
+
* The event `monster-change` is sent as soon as someone has clicked on a input control.
|
|
268
|
+
* `monster-changed` is sent as soon as the control has processed this input.
|
|
269
|
+
* The `monster-changed` event is sent when setting a selection. If the options have been set, the `monster-options-set` event is sent.
|
|
270
|
+
*
|
|
271
|
+
* The CustomEvent has the property [`detail`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/detail).
|
|
272
|
+
*
|
|
273
|
+
* ```
|
|
274
|
+
* node.addEventListener('monster-change',(e)=>console.log(e.detail))
|
|
275
|
+
* node.addEventListener('monster-changed',(e)=>console.log(e.detail))
|
|
276
|
+
* node.addEventListener('monster-selected',(e)=>console.log(e.detail))
|
|
277
|
+
* node.addEventListener('monster-options-set',(e)=>console.log(e.detail))
|
|
278
|
+
* ```
|
|
279
|
+
*
|
|
280
|
+
* @externalExample ../../../example/components/form/select.mjs
|
|
281
|
+
* @startuml select.png
|
|
282
|
+
* skinparam monochrome true
|
|
283
|
+
* skinparam shadowing false
|
|
284
|
+
* HTMLElement <|-- CustomElement
|
|
285
|
+
* CustomElement <|-- CustomControl
|
|
286
|
+
* CustomControl <|-- Select
|
|
287
|
+
* @enduml
|
|
288
|
+
*
|
|
289
|
+
* @since 1.0.0
|
|
290
|
+
* @copyright schukai GmbH
|
|
291
|
+
* @memberOf Monster.Components.Form
|
|
292
|
+
* @summary A highly configurable select control
|
|
293
|
+
* @fires Monster.Components.Form.event:monster-options-set
|
|
294
|
+
* @fires Monster.Components.Form.event:monster-selected
|
|
295
|
+
* @fires Monster.Components.Form.event:monster-change
|
|
296
|
+
* @fires Monster.Components.Form.event:monster-changed
|
|
297
|
+
*/
|
|
298
|
+
class Select extends CustomControl {
|
|
299
|
+
/**
|
|
300
|
+
* @extends CustomControl
|
|
301
|
+
*/
|
|
302
|
+
constructor() {
|
|
303
|
+
super();
|
|
304
|
+
initOptionObserver.call(this);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* This method is called by the `instanceof` operator.
|
|
309
|
+
* @returns {symbol}
|
|
310
|
+
* @since 2.1.0
|
|
311
|
+
*/
|
|
312
|
+
static get [instanceSymbol]() {
|
|
313
|
+
return Symbol.for("@schukai/component-form/select@@instance");
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* The current selection of the Select
|
|
318
|
+
*
|
|
319
|
+
* ```
|
|
320
|
+
* e = document.querySelector('monster-select');
|
|
321
|
+
* console.log(e.value)
|
|
322
|
+
* // ↦ 1
|
|
323
|
+
* // ↦ ['1','2']
|
|
324
|
+
* ```
|
|
325
|
+
*
|
|
326
|
+
* @property {string|array}
|
|
327
|
+
*/
|
|
328
|
+
get value() {
|
|
329
|
+
return convertSelectionToValue.call(this, this.getOption("selection"));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals}
|
|
334
|
+
* @return {boolean}
|
|
335
|
+
*/
|
|
336
|
+
static get formAssociated() {
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Set selection
|
|
342
|
+
*
|
|
343
|
+
* ```
|
|
344
|
+
* e = document.querySelector('monster-select');
|
|
345
|
+
* e.value=1
|
|
346
|
+
* ```
|
|
347
|
+
*
|
|
348
|
+
* @property {string|array} value
|
|
349
|
+
* @since 1.2.0
|
|
350
|
+
* @throws {Error} unsupported type
|
|
351
|
+
*/
|
|
352
|
+
set value(value) {;
|
|
353
|
+
|
|
354
|
+
const result = convertValueToSelection.call(this, value);
|
|
355
|
+
setSelection
|
|
356
|
+
.call(this, result.selection)
|
|
357
|
+
.then(() => {})
|
|
358
|
+
.catch((e) => {
|
|
359
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* To set the options via the html tag the attribute `data-monster-options` must be used.
|
|
365
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
|
366
|
+
*
|
|
367
|
+
* The individual configuration values can be found in the table.
|
|
368
|
+
*
|
|
369
|
+
* @property {Object} toggleEventType=click,touch List of event types to be observed for opening the dropdown
|
|
370
|
+
* @property {boolean} delegatesFocus=false lorem [see mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/delegatesFocus)
|
|
371
|
+
* @property {Object[]} options Selection of key identifier pairs available for selection and displayed in the dropdown.
|
|
372
|
+
* @property {string} options[].label Label
|
|
373
|
+
* @property {string} options[].value Value
|
|
374
|
+
* @property {string} options[].visibility hidden or visible
|
|
375
|
+
* @property {Array} selection Selected options
|
|
376
|
+
* @property {Integer} showMaxOptions=10 Maximum number of visible options before a scroll bar should be displayed.
|
|
377
|
+
* @property {string} type=radio Multiple (checkbox) or single selection (radio)
|
|
378
|
+
* @property {string} name=(random id) Name of the form field
|
|
379
|
+
* @property {string} url Load options from server per url
|
|
380
|
+
* @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
|
|
381
|
+
* @property {String} fetch.redirect=error
|
|
382
|
+
* @property {String} fetch.method=GET
|
|
383
|
+
* @property {String} fetch.mode=same-origin
|
|
384
|
+
* @property {String} fetch.credentials=same-origin
|
|
385
|
+
* @property {Object} fetch.headers={"accept":"application/json"}}
|
|
386
|
+
* @property {Object} labels
|
|
387
|
+
* @property {string} labels.cannot-be-loaded cannot be loaded
|
|
388
|
+
* @property {string} labels.no-options-available no options available
|
|
389
|
+
* @property {string} labels.select-an-option select an option
|
|
390
|
+
* @property {string} labels.no-option no option in the list, maybe you have to change the filter
|
|
391
|
+
* @property {Object} features List with features
|
|
392
|
+
* @property {Boolean} features.clearAll=true Display of a delete button to delete the entire selection
|
|
393
|
+
* @property {Boolean} features.clear=true Display of a delete key for deleting the specific selection
|
|
394
|
+
* @property {Boolean} features.loadOnOpen=false Load options when opening the dropdown
|
|
395
|
+
* @property {Boolean} filter.defaultValue=* Default filter value, if the filter is empty
|
|
396
|
+
* @property {Boolean} filter.mode=options Filter mode, values: options, remote, disabled
|
|
397
|
+
* @property {Object} templates Template definitions
|
|
398
|
+
* @property {string} templates.main Main template
|
|
399
|
+
* @property {string} templateMapping Mapping of the template placeholders
|
|
400
|
+
* @property {string} templateMapping.selected Selected Template
|
|
401
|
+
* @property {Object} popper [PopperJS Options](https://popper.js.org/docs/v2/)
|
|
402
|
+
* @property {string} popper.placement=bottom PopperJS placement
|
|
403
|
+
* @property {Object[]} modifiers={name:offset} PopperJS placement
|
|
404
|
+
* @property {Object} mapping
|
|
405
|
+
* @property {String} mapping.selector=* Path to select the appropriate entries
|
|
406
|
+
* @property {String} mapping.labelTemplate="" template with the label placeholders in the form ${name}, where name is the key (**)
|
|
407
|
+
* @property {String} mapping.valueTemplate="" template with the value placeholders in the form ${name}, where name is the key
|
|
408
|
+
* @property {Monster.Components.Form~exampleFilterCallback|undefined} mapping.filter Filtering of values via a function
|
|
409
|
+
* @property {Object} formatter
|
|
410
|
+
* @property {Monster.Components.Form~formatterSelectionCallback|undefined} formatter.selection format selection label
|
|
411
|
+
*/
|
|
412
|
+
get defaults() {
|
|
413
|
+
return Object.assign(
|
|
414
|
+
{},
|
|
415
|
+
super.defaults,
|
|
416
|
+
{
|
|
417
|
+
toggleEventType: ["click", "touch"],
|
|
418
|
+
delegatesFocus: false,
|
|
419
|
+
options: [],
|
|
420
|
+
selection: [],
|
|
421
|
+
showMaxOptions: 10,
|
|
422
|
+
type: "radio",
|
|
423
|
+
name: new ID("s").toString(),
|
|
424
|
+
features: {
|
|
425
|
+
clearAll: true,
|
|
426
|
+
clear: true,
|
|
427
|
+
loadOnOpen: false,
|
|
428
|
+
},
|
|
429
|
+
url: null,
|
|
430
|
+
labels: {
|
|
431
|
+
"cannot-be-loaded": "Cannot be loaded",
|
|
432
|
+
"no-options-available": "No options available",
|
|
433
|
+
"select-an-option": "Select an option",
|
|
434
|
+
"summary-text": {
|
|
435
|
+
zero: "No entries were selected",
|
|
436
|
+
one: '<span class="monster-badge-primary-pill">1</span> entry was selected',
|
|
437
|
+
other:
|
|
438
|
+
'<span class="monster-badge-primary-pill">${count}</span> entries were selected',
|
|
439
|
+
},
|
|
440
|
+
"no-options":
|
|
441
|
+
"Unfortunately, there are no options available in the list.",
|
|
442
|
+
"no-options-found":
|
|
443
|
+
"No options are available in the list. Please consider modifying the filter.",
|
|
444
|
+
},
|
|
445
|
+
messages: {
|
|
446
|
+
control: null,
|
|
447
|
+
selected: null,
|
|
448
|
+
emptyOptions: null,
|
|
449
|
+
},
|
|
450
|
+
fetch: {
|
|
451
|
+
redirect: "error",
|
|
452
|
+
method: "GET",
|
|
453
|
+
mode: "same-origin",
|
|
454
|
+
credentials: "same-origin",
|
|
455
|
+
headers: {
|
|
456
|
+
accept: "application/json",
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
filter: {
|
|
460
|
+
defaultValue: "*",
|
|
461
|
+
mode: "disabled",
|
|
462
|
+
position: "inline",
|
|
463
|
+
},
|
|
464
|
+
classes: {
|
|
465
|
+
badge: "monster-badge-primary",
|
|
466
|
+
statusOrRemoveBadge: "empty",
|
|
467
|
+
},
|
|
468
|
+
mapping: {
|
|
469
|
+
selector: "*",
|
|
470
|
+
labelTemplate: "",
|
|
471
|
+
valueTemplate: "",
|
|
472
|
+
filter: null,
|
|
473
|
+
},
|
|
474
|
+
formatter: {
|
|
475
|
+
selection: buildSelectionLabel,
|
|
476
|
+
},
|
|
477
|
+
templates: {
|
|
478
|
+
main: getTemplate(),
|
|
479
|
+
},
|
|
480
|
+
templateMapping: {
|
|
481
|
+
/** with the attribute `data-monster-selected-template` the template for the selected options can be defined. */
|
|
482
|
+
selected: getSelectionTemplate(),
|
|
483
|
+
},
|
|
484
|
+
|
|
485
|
+
popper: {
|
|
486
|
+
placement: "bottom",
|
|
487
|
+
middleware: ["flip", "offset:1"],
|
|
488
|
+
},
|
|
489
|
+
},
|
|
490
|
+
initOptionsFromArguments.call(this),
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
*
|
|
496
|
+
* @return {Monster.Components.Form.Select}
|
|
497
|
+
*/
|
|
498
|
+
[assembleMethodSymbol]() {
|
|
499
|
+
const self = this;
|
|
500
|
+
super[assembleMethodSymbol]();
|
|
501
|
+
|
|
502
|
+
initControlReferences.call(self);
|
|
503
|
+
initEventhandler.call(self);
|
|
504
|
+
|
|
505
|
+
if (
|
|
506
|
+
self.getOption("url") !== null &&
|
|
507
|
+
self.getOption("features.loadOnOpen") !== true
|
|
508
|
+
) {
|
|
509
|
+
self
|
|
510
|
+
.fetch()
|
|
511
|
+
.then(() => {
|
|
512
|
+
let result;
|
|
513
|
+
if (self.hasAttribute("value")) {
|
|
514
|
+
result = setSelection.call(self, self.getAttribute("value"));
|
|
515
|
+
} else {
|
|
516
|
+
result = setSelection.call(self, []);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
result
|
|
520
|
+
.then(() => {})
|
|
521
|
+
.catch((e) => {
|
|
522
|
+
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`);
|
|
523
|
+
});
|
|
524
|
+
})
|
|
525
|
+
.catch((e) => {
|
|
526
|
+
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`);
|
|
527
|
+
throw e;
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
let lastValue = self.value;
|
|
532
|
+
self[internalSymbol].attachObserver(
|
|
533
|
+
new Observer(function () {
|
|
534
|
+
if (isObject(this) && this instanceof ProxyObserver) {
|
|
535
|
+
const n = this.getSubject()?.options?.value;
|
|
536
|
+
|
|
537
|
+
if (lastValue !== n) {
|
|
538
|
+
lastValue = n;
|
|
539
|
+
setSelection
|
|
540
|
+
.call(self, n)
|
|
541
|
+
.then(() => {})
|
|
542
|
+
.catch((e) => {
|
|
543
|
+
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`);
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}),
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
areOptionsAvailableAndInit.call(self);
|
|
551
|
+
|
|
552
|
+
return this;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* The Button.click() method simulates a click on the internal button element.
|
|
557
|
+
*
|
|
558
|
+
* @since 3.27.0
|
|
559
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click}
|
|
560
|
+
*/
|
|
561
|
+
click() {;
|
|
562
|
+
if (this.getOption("disabled") === true) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
toggle.call(this);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* The Button.focus() method sets focus on the internal button element.
|
|
571
|
+
*
|
|
572
|
+
* @since 3.27.0
|
|
573
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus}
|
|
574
|
+
*/
|
|
575
|
+
focus(options) {;
|
|
576
|
+
if (this.getOption("disabled") === true) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
new Processing(() => {
|
|
581
|
+
gatherState.call(this);
|
|
582
|
+
focusFilter.call(this, options);
|
|
583
|
+
})
|
|
584
|
+
.run()
|
|
585
|
+
.catch((e) => {
|
|
586
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* The Button.blur() method removes focus from the internal button element.
|
|
592
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/blur
|
|
593
|
+
*/
|
|
594
|
+
blur() {;
|
|
595
|
+
new Processing(() => {
|
|
596
|
+
gatherState.call(this);
|
|
597
|
+
blurFilter.call(this);
|
|
598
|
+
})
|
|
599
|
+
.run()
|
|
600
|
+
.catch((e) => {
|
|
601
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* If no url is specified, the options are taken from the Component itself.
|
|
607
|
+
*
|
|
608
|
+
* @param {string|URL} url URL to fetch the options
|
|
609
|
+
* @return {Promise}
|
|
610
|
+
*/
|
|
611
|
+
fetch(url) {;
|
|
612
|
+
|
|
613
|
+
if (url instanceof URL) {
|
|
614
|
+
url = url.toString();
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
if (url !== undefined && url !== null) {
|
|
618
|
+
url = validateString(url);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return fetchData.call(this, url).then((map) => {
|
|
622
|
+
if (
|
|
623
|
+
isObject(map) ||
|
|
624
|
+
isArray(map) | (map instanceof Set) ||
|
|
625
|
+
map instanceof Map
|
|
626
|
+
) {
|
|
627
|
+
this.importOptions(map);
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* @return {void}
|
|
634
|
+
*/
|
|
635
|
+
connectedCallback() {
|
|
636
|
+
super.connectedCallback();
|
|
637
|
+
const document = getDocument();;
|
|
638
|
+
|
|
639
|
+
for (const [, type] of Object.entries(["click", "touch"])) {
|
|
640
|
+
// close on outside ui-events
|
|
641
|
+
document.addEventListener(type, this[closeEventHandler]);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
parseSlotsToOptions.call(this);
|
|
645
|
+
attachResizeObserver.call(this);
|
|
646
|
+
updatePopper.call(this);
|
|
647
|
+
|
|
648
|
+
new Processing(() => {
|
|
649
|
+
gatherState.call(this);
|
|
650
|
+
focusFilter.call(this);
|
|
651
|
+
}).run();
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* @return {void}
|
|
656
|
+
*/
|
|
657
|
+
disconnectedCallback() {
|
|
658
|
+
super.disconnectedCallback();
|
|
659
|
+
const document = getDocument();;
|
|
660
|
+
|
|
661
|
+
// close on outside ui-events
|
|
662
|
+
for (const [, type] of Object.entries(["click", "touch"])) {
|
|
663
|
+
document.removeEventListener(type, this[closeEventHandler]);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
disconnectResizeObserver.call(this);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Import Select Options from dataset
|
|
671
|
+
* Not to be confused with the control defaults/options
|
|
672
|
+
*
|
|
673
|
+
* @since 0.16.0
|
|
674
|
+
* @param {array|object|Map|Set} data
|
|
675
|
+
* @return {Select}
|
|
676
|
+
* @throws {Error} map is not iterable
|
|
677
|
+
* @throws {Error} missing label configuration
|
|
678
|
+
*/
|
|
679
|
+
importOptions(data) {;
|
|
680
|
+
|
|
681
|
+
const mappingOptions = this.getOption("mapping", {});
|
|
682
|
+
const selector = mappingOptions?.["selector"];
|
|
683
|
+
const labelTemplate = mappingOptions?.["labelTemplate"];
|
|
684
|
+
const valueTemplate = mappingOptions?.["valueTemplate"];
|
|
685
|
+
const filter = mappingOptions?.["filter"];
|
|
686
|
+
|
|
687
|
+
let flag = false;
|
|
688
|
+
if (labelTemplate === "") {
|
|
689
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty label template");
|
|
690
|
+
flag = true;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
if (valueTemplate === "") {
|
|
694
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty value template");
|
|
695
|
+
flag = true;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
if (flag === true) {
|
|
699
|
+
throw new Error("missing label configuration");
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
const map = buildMap(data, selector, labelTemplate, valueTemplate, filter);
|
|
703
|
+
|
|
704
|
+
const options = [];
|
|
705
|
+
if (!isIterable(map)) {
|
|
706
|
+
throw new Error("map is not iterable");
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
const visibility = "visible";
|
|
710
|
+
|
|
711
|
+
map.forEach((label, value) => {
|
|
712
|
+
options.push({
|
|
713
|
+
value,
|
|
714
|
+
label,
|
|
715
|
+
visibility,
|
|
716
|
+
});
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
runAsOptionLengthChanged.call(this, map.size);
|
|
720
|
+
this.setOption("options", options);
|
|
721
|
+
|
|
722
|
+
fireCustomEvent(this, "monster-options-set", {
|
|
723
|
+
options,
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
return this;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
/**
|
|
730
|
+
* @private
|
|
731
|
+
* @return {Monster.Components.Form.Select}
|
|
732
|
+
*/
|
|
733
|
+
calcAndSetOptionsDimension() {
|
|
734
|
+
calcAndSetOptionsDimension.call(this);
|
|
735
|
+
return this;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
*
|
|
740
|
+
* @return {string}
|
|
741
|
+
*/
|
|
742
|
+
static getTag() {
|
|
743
|
+
return "monster-select";
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/**
|
|
747
|
+
*
|
|
748
|
+
* @return {CSSStyleSheet[]}
|
|
749
|
+
*/
|
|
750
|
+
static getCSSStyleSheet() {
|
|
751
|
+
return [SelectStyleSheet];
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/**
|
|
756
|
+
* This attribute can be used to pass a URL to this select.
|
|
757
|
+
*
|
|
758
|
+
* ```
|
|
759
|
+
* <monster-select data-monster-url="https://example.com/"></monster-select>
|
|
760
|
+
* ```
|
|
761
|
+
*
|
|
762
|
+
* @private
|
|
763
|
+
* @return {object}
|
|
764
|
+
*/
|
|
765
|
+
function initOptionsFromArguments() {;
|
|
766
|
+
const options = {};
|
|
767
|
+
|
|
768
|
+
const template = this.getAttribute("data-monster-selected-template");
|
|
769
|
+
if (isString(template)) {
|
|
770
|
+
if (!options["templateMapping"]) options["templateMapping"] = {};
|
|
771
|
+
|
|
772
|
+
switch (template) {
|
|
773
|
+
case "summary":
|
|
774
|
+
case "default":
|
|
775
|
+
options["templateMapping"]["selected"] = getSummaryTemplate();
|
|
776
|
+
break;
|
|
777
|
+
case "selected":
|
|
778
|
+
options["templateMapping"]["selected"] = getSelectionTemplate();
|
|
779
|
+
break;
|
|
780
|
+
default:
|
|
781
|
+
addAttributeToken(
|
|
782
|
+
this,
|
|
783
|
+
ATTRIBUTE_ERRORMESSAGE,
|
|
784
|
+
"invalid template, use summary or selected",
|
|
785
|
+
);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
return options;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* @private
|
|
794
|
+
*/
|
|
795
|
+
function attachResizeObserver() {;
|
|
796
|
+
|
|
797
|
+
// against flickering
|
|
798
|
+
this[resizeObserverSymbol] = new ResizeObserver((entries) => {
|
|
799
|
+
if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
|
|
800
|
+
try {
|
|
801
|
+
this[timerCallbackSymbol].touch();
|
|
802
|
+
return;
|
|
803
|
+
} catch (e) {
|
|
804
|
+
delete this[timerCallbackSymbol];
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
|
|
809
|
+
updatePopper.call(this);
|
|
810
|
+
delete this[timerCallbackSymbol];
|
|
811
|
+
});
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
this[resizeObserverSymbol].observe(this.parentElement);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
function disconnectResizeObserver() {;
|
|
818
|
+
if (this[resizeObserverSymbol] instanceof ResizeObserver) {
|
|
819
|
+
this[resizeObserverSymbol].disconnect();
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
function getSelectionTemplate() {
|
|
824
|
+
return `<div data-monster-role="selection"
|
|
825
|
+
data-monster-insert="selection path:selection" role="search"
|
|
826
|
+
><input type="text" role="searchbox"
|
|
827
|
+
part="inline-filter" name="inline-filter"
|
|
828
|
+
data-monster-role="filter"
|
|
829
|
+
autocomplete="off"
|
|
830
|
+
tabindex="0"
|
|
831
|
+
><div data-monster-replace="path:messages.control"></div>
|
|
832
|
+
</div>`;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
function getSummaryTemplate() {
|
|
836
|
+
return `<div data-monster-role="selection" role="search">
|
|
837
|
+
<input type="text" role="searchbox"
|
|
838
|
+
part="inline-filter" name="inline-filter"
|
|
839
|
+
data-monster-role="filter"
|
|
840
|
+
autocomplete="off"
|
|
841
|
+
tabindex="0"
|
|
842
|
+
>
|
|
843
|
+
<div data-monster-replace="path:messages.selected"></div>
|
|
844
|
+
</div>`;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* @return {void}
|
|
849
|
+
* @private
|
|
850
|
+
*/
|
|
851
|
+
function parseSlotsToOptions() {;
|
|
852
|
+
|
|
853
|
+
let options = this.getOption("options");
|
|
854
|
+
if (!isIterable(options)) {
|
|
855
|
+
options = [];
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
let counter = 1;
|
|
859
|
+
getSlottedElements.call(this, "div").forEach((node) => {
|
|
860
|
+
let value = String(counter++);
|
|
861
|
+
let visibility = "visible";
|
|
862
|
+
|
|
863
|
+
if (node.hasAttribute("data-monster-value")) {
|
|
864
|
+
value = node.getAttribute("data-monster-value");
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
if (node.style.display === "none") {
|
|
868
|
+
visibility = "hidden";
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const label = node.outerHTML;
|
|
872
|
+
|
|
873
|
+
options.push({
|
|
874
|
+
value,
|
|
875
|
+
label,
|
|
876
|
+
visibility,
|
|
877
|
+
});
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
runAsOptionLengthChanged.call(this, options.length);
|
|
881
|
+
this.setOption("options", options);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* wait until all options are finished rendering
|
|
886
|
+
*
|
|
887
|
+
* @private
|
|
888
|
+
* @param {int} targetLength
|
|
889
|
+
*/
|
|
890
|
+
function runAsOptionLengthChanged(targetLength) {
|
|
891
|
+
const self = this;
|
|
892
|
+
|
|
893
|
+
if (!self[optionsElementSymbol]) {
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
const callback = function (mutationsList, observer) {
|
|
898
|
+
const run = false;
|
|
899
|
+
for (const mutation of mutationsList) {
|
|
900
|
+
if (mutation.type === "childList") {
|
|
901
|
+
const run = true;
|
|
902
|
+
break;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
if (run === true) {
|
|
907
|
+
const nodes = self[optionsElementSymbol].querySelectorAll(
|
|
908
|
+
`div[${ATTRIBUTE_ROLE}=option]`,
|
|
909
|
+
);
|
|
910
|
+
|
|
911
|
+
if (nodes.length === targetLength) {
|
|
912
|
+
checkOptionState.call(self);
|
|
913
|
+
observer.disconnect();
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
const observer = new MutationObserver(callback);
|
|
919
|
+
observer.observe(self[optionsElementSymbol], {
|
|
920
|
+
attributes: false,
|
|
921
|
+
childList: true,
|
|
922
|
+
subtree: true,
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
/**
|
|
927
|
+
* @private
|
|
928
|
+
* @param {*} value
|
|
929
|
+
* @return {*}
|
|
930
|
+
*/
|
|
931
|
+
function buildSelectionLabel(value) {;
|
|
932
|
+
const options = this.getOption("options");
|
|
933
|
+
|
|
934
|
+
for (let i = 0; i < options.length; i++) {
|
|
935
|
+
const o = options?.[i];
|
|
936
|
+
if (isObject(o) && o?.["value"] === value) {
|
|
937
|
+
return o?.["label"];
|
|
938
|
+
} else if (isPrimitive(o) && o === value) {
|
|
939
|
+
return o;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
return undefined;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* @private
|
|
948
|
+
* @param {*} value
|
|
949
|
+
* @return {string}
|
|
950
|
+
* @throws {Error} no value found
|
|
951
|
+
*/
|
|
952
|
+
function getSelectionLabel(value) {;
|
|
953
|
+
|
|
954
|
+
const callback = this.getOption("formatter.selection");
|
|
955
|
+
if (isFunction(callback)) {
|
|
956
|
+
const label = callback.call(this, value);
|
|
957
|
+
if (isString(label)) return label;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
if (isString(value) || isInteger(value)) {
|
|
961
|
+
return `${value}`;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
return this.getOption("labels.cannot-be-loaded", value);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* @private
|
|
969
|
+
* @param {Event} event
|
|
970
|
+
*/
|
|
971
|
+
function handleToggleKeyboardEvents(event) {;
|
|
972
|
+
|
|
973
|
+
switch (event?.["code"]) {
|
|
974
|
+
case "Escape":
|
|
975
|
+
toggle.call(this);
|
|
976
|
+
event.preventDefault();
|
|
977
|
+
break;
|
|
978
|
+
case "Space":
|
|
979
|
+
toggle.call(this);
|
|
980
|
+
event.preventDefault();
|
|
981
|
+
break;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* @license AGPLv3
|
|
987
|
+
* @since 1.15.0
|
|
988
|
+
* @private
|
|
989
|
+
* @this CustomElement
|
|
990
|
+
*/
|
|
991
|
+
function initOptionObserver() {
|
|
992
|
+
const self = this;
|
|
993
|
+
|
|
994
|
+
self.attachObserver(
|
|
995
|
+
new Observer(function () {
|
|
996
|
+
new Processing(() => {
|
|
997
|
+
try {
|
|
998
|
+
self.updateI18n();
|
|
999
|
+
} catch (e) {}
|
|
1000
|
+
try {
|
|
1001
|
+
areOptionsAvailableAndInit.call(self);
|
|
1002
|
+
} catch (e) {}
|
|
1003
|
+
|
|
1004
|
+
setSummaryAndControlText.call(self);
|
|
1005
|
+
}).run();
|
|
1006
|
+
}),
|
|
1007
|
+
);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
function getDefaultTranslation() {;
|
|
1011
|
+
|
|
1012
|
+
const translation = new Translations("en").assignTranslations(
|
|
1013
|
+
this.getOption("labels", {}),
|
|
1014
|
+
);
|
|
1015
|
+
|
|
1016
|
+
try {
|
|
1017
|
+
const doc = getDocumentTranslations();
|
|
1018
|
+
translation.locale = doc.locale;
|
|
1019
|
+
} catch (e) {}
|
|
1020
|
+
|
|
1021
|
+
return translation;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* @private
|
|
1026
|
+
* @returns {string|*}
|
|
1027
|
+
*/
|
|
1028
|
+
function setSummaryAndControlText() {;
|
|
1029
|
+
|
|
1030
|
+
const translations = getDefaultTranslation.call(this);
|
|
1031
|
+
const selections = this.getOption("selection");
|
|
1032
|
+
|
|
1033
|
+
const text = translations.getPluralRuleText(
|
|
1034
|
+
"summary-text",
|
|
1035
|
+
selections.length,
|
|
1036
|
+
"",
|
|
1037
|
+
);
|
|
1038
|
+
|
|
1039
|
+
const selectedText = new Formatter({
|
|
1040
|
+
count: String(selections.length),
|
|
1041
|
+
}).format(text);
|
|
1042
|
+
|
|
1043
|
+
this.setOption("messages.selected", selectedText);
|
|
1044
|
+
|
|
1045
|
+
const current = this.getOption("messages.control");
|
|
1046
|
+
const msg = this.getOption("labels.select-an-option");
|
|
1047
|
+
|
|
1048
|
+
if (
|
|
1049
|
+
current === "" ||
|
|
1050
|
+
current === undefined ||
|
|
1051
|
+
current === msg ||
|
|
1052
|
+
current === null
|
|
1053
|
+
) {
|
|
1054
|
+
if (selections === undefined || selections.length === 0) {
|
|
1055
|
+
this.setOption("messages.control", msg);
|
|
1056
|
+
} else {
|
|
1057
|
+
this.setOption("messages.control", "");
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
/**
|
|
1063
|
+
* @private
|
|
1064
|
+
* @return {NodeList}
|
|
1065
|
+
*/
|
|
1066
|
+
function getOptionElements() {
|
|
1067
|
+
return this[optionsElementSymbol].querySelectorAll(
|
|
1068
|
+
`[${ATTRIBUTE_ROLE}=option]`,
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* With the help of this filter callback, values can be filtered out. Only if the filter function returns true, the value is taken for the map.
|
|
1074
|
+
*
|
|
1075
|
+
* @callback Monster.Components.Form~exampleFilterCallback
|
|
1076
|
+
* @param {*} value Value
|
|
1077
|
+
* @param {string} key Key
|
|
1078
|
+
* @memberOf Monster.Components.Form
|
|
1079
|
+
* @see Monster.Data.buildMap
|
|
1080
|
+
*/
|
|
1081
|
+
|
|
1082
|
+
/**
|
|
1083
|
+
*
|
|
1084
|
+
* @callback Monster.Components.Form~formatterSelectionCallback
|
|
1085
|
+
* @param {*} value Value
|
|
1086
|
+
* @return {string|undefined}
|
|
1087
|
+
* @memberOf Monster.Components.Form
|
|
1088
|
+
* @see Monster.Data.buildMap
|
|
1089
|
+
*/
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* @private
|
|
1093
|
+
*/
|
|
1094
|
+
function calcAndSetOptionsDimension() {;
|
|
1095
|
+
|
|
1096
|
+
const options = getOptionElements.call(this);
|
|
1097
|
+
const container = this[optionsElementSymbol];
|
|
1098
|
+
if (!(container instanceof HTMLElement && options instanceof NodeList)) {
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
let visible = 0;
|
|
1103
|
+
let optionHeight = 0;
|
|
1104
|
+
const max = this.getOption("showMaxOptions", 10);
|
|
1105
|
+
|
|
1106
|
+
let scrollFlag = false;
|
|
1107
|
+
for (const [, option] of Object.entries(options)) {
|
|
1108
|
+
const computedStyle = getGlobal().getComputedStyle(option);
|
|
1109
|
+
if (computedStyle.display === "none") continue;
|
|
1110
|
+
|
|
1111
|
+
let h = option.getBoundingClientRect().height;
|
|
1112
|
+
h += parseInt(computedStyle.getPropertyValue("margin-top"), 10);
|
|
1113
|
+
h += parseInt(computedStyle.getPropertyValue("margin-bottom"), 10);
|
|
1114
|
+
optionHeight = Math.max(optionHeight, h);
|
|
1115
|
+
|
|
1116
|
+
visible++;
|
|
1117
|
+
if (visible > max) {
|
|
1118
|
+
break;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
if (visible > max) {
|
|
1123
|
+
visible = max;
|
|
1124
|
+
scrollFlag = true;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
if (visible === 0) {
|
|
1128
|
+
if (this.getOption("options").length === 0) {
|
|
1129
|
+
this.setOption(
|
|
1130
|
+
"messages.emptyOptions",
|
|
1131
|
+
this.getOption("labels.no-options-available"),
|
|
1132
|
+
);
|
|
1133
|
+
} else {
|
|
1134
|
+
this.setOption(
|
|
1135
|
+
"messages.emptyOptions",
|
|
1136
|
+
this.getOption("labels.no-options-found"),
|
|
1137
|
+
);
|
|
1138
|
+
}
|
|
1139
|
+
this[noOptionsAvailableElementSymbol].classList.remove("d-none");
|
|
1140
|
+
} else {
|
|
1141
|
+
this[noOptionsAvailableElementSymbol].classList.add("d-none");
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
const styles = getGlobal().getComputedStyle(this[optionsElementSymbol]);
|
|
1145
|
+
let padding = parseInt(styles.getPropertyValue("padding-top"), 10);
|
|
1146
|
+
padding += parseInt(styles.getPropertyValue("padding-bottom"), 10);
|
|
1147
|
+
|
|
1148
|
+
let margin = parseInt(styles.getPropertyValue("margin-top"), 10);
|
|
1149
|
+
margin += parseInt(styles.getPropertyValue("margin-bottom"), 10);
|
|
1150
|
+
|
|
1151
|
+
const containerHeight = optionHeight * visible + padding + margin;
|
|
1152
|
+
container.style.height = `${containerHeight}px`;
|
|
1153
|
+
|
|
1154
|
+
if (scrollFlag === true) {
|
|
1155
|
+
container.style.overflowY = "scroll";
|
|
1156
|
+
} else {
|
|
1157
|
+
container.style.overflowY = "auto";
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
const domRect = this[controlElementSymbol].getBoundingClientRect();
|
|
1161
|
+
|
|
1162
|
+
this[popperElementSymbol].style.width = `${domRect.width}px`;
|
|
1163
|
+
container.style.overflowX = "auto";
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
/**
|
|
1167
|
+
* @private
|
|
1168
|
+
* @param {number} direction
|
|
1169
|
+
* @throws {Error} no shadow-root is defined
|
|
1170
|
+
*/
|
|
1171
|
+
function activateCurrentOption(direction) {;
|
|
1172
|
+
|
|
1173
|
+
if (!this.shadowRoot) {
|
|
1174
|
+
throw new Error("no shadow-root is defined");
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
let focused = this.shadowRoot.querySelector(`[${ATTRIBUTE_PREFIX}focused]`);
|
|
1178
|
+
|
|
1179
|
+
if (
|
|
1180
|
+
!(focused instanceof HTMLElement) ||
|
|
1181
|
+
focused.matches("[data-monster-visibility=hidden]")
|
|
1182
|
+
) {
|
|
1183
|
+
for (const [, e] of Object.entries(
|
|
1184
|
+
this.shadowRoot.querySelectorAll(`[${ATTRIBUTE_ROLE}=option]`),
|
|
1185
|
+
)) {
|
|
1186
|
+
if (e.matches("[data-monster-visibility=visible]")) {
|
|
1187
|
+
focused = e;
|
|
1188
|
+
break;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
} else {
|
|
1192
|
+
if (direction === FOCUS_DIRECTION_DOWN) {
|
|
1193
|
+
while (focused.nextSibling) {
|
|
1194
|
+
focused = focused.nextSibling;
|
|
1195
|
+
|
|
1196
|
+
if (
|
|
1197
|
+
focused instanceof HTMLElement &&
|
|
1198
|
+
focused.hasAttribute(ATTRIBUTE_ROLE) &&
|
|
1199
|
+
focused.getAttribute(ATTRIBUTE_ROLE) === "option" &&
|
|
1200
|
+
focused.matches("[data-monster-visibility=visible]") &&
|
|
1201
|
+
focused.matches(":not([data-monster-filtered=true])")
|
|
1202
|
+
) {
|
|
1203
|
+
break;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
} else {
|
|
1207
|
+
while (focused.previousSibling) {
|
|
1208
|
+
focused = focused.previousSibling;
|
|
1209
|
+
|
|
1210
|
+
if (
|
|
1211
|
+
focused instanceof HTMLElement &&
|
|
1212
|
+
focused.hasAttribute(ATTRIBUTE_ROLE) &&
|
|
1213
|
+
focused.getAttribute(ATTRIBUTE_ROLE) === "option" &&
|
|
1214
|
+
focused.matches("[data-monster-visibility=visible]") &&
|
|
1215
|
+
focused.matches(":not([data-monster-filtered=true])")
|
|
1216
|
+
) {
|
|
1217
|
+
break;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
new Processing(() => {
|
|
1224
|
+
if (focused instanceof HTMLElement) {
|
|
1225
|
+
this.shadowRoot
|
|
1226
|
+
.querySelectorAll(`[${ATTRIBUTE_PREFIX}focused]`)
|
|
1227
|
+
.forEach((e) => {
|
|
1228
|
+
e.removeAttribute(`${ATTRIBUTE_PREFIX}focused`);
|
|
1229
|
+
});
|
|
1230
|
+
|
|
1231
|
+
focused.focus();
|
|
1232
|
+
focused.setAttribute(`${ATTRIBUTE_PREFIX}focused`, true);
|
|
1233
|
+
}
|
|
1234
|
+
}).run();
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
/**
|
|
1238
|
+
* @private
|
|
1239
|
+
*/
|
|
1240
|
+
function filterOptions() {;
|
|
1241
|
+
|
|
1242
|
+
new Processing(() => {
|
|
1243
|
+
let filterValue;
|
|
1244
|
+
|
|
1245
|
+
switch (this.getOption("filter.position")) {
|
|
1246
|
+
case FILTER_POSITION_INLINE:
|
|
1247
|
+
if (this[inlineFilterElementSymbol] instanceof HTMLElement) {
|
|
1248
|
+
filterValue = this[inlineFilterElementSymbol].value.toLowerCase();
|
|
1249
|
+
} else {
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
break;
|
|
1254
|
+
case FILTER_POSITION_POPPER:
|
|
1255
|
+
default:
|
|
1256
|
+
if (this[popperFilterElementSymbol] instanceof HTMLInputElement) {
|
|
1257
|
+
filterValue = this[popperFilterElementSymbol].value.toLowerCase();
|
|
1258
|
+
} else {
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
const options = this.getOption("options");
|
|
1264
|
+
for (const [i, option] of Object.entries(options)) {
|
|
1265
|
+
if (option.label.toLowerCase().indexOf(filterValue) === -1) {
|
|
1266
|
+
this.setOption(`options.${i}.filtered`, "true");
|
|
1267
|
+
} else {
|
|
1268
|
+
this.setOption(`options.${i}.filtered`, undefined);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
})
|
|
1272
|
+
.run()
|
|
1273
|
+
.then(() => {
|
|
1274
|
+
new Processing(10, () => {
|
|
1275
|
+
calcAndSetOptionsDimension.call(this);
|
|
1276
|
+
focusFilter.call(this);
|
|
1277
|
+
}).run();
|
|
1278
|
+
})
|
|
1279
|
+
.catch((e) => {
|
|
1280
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
/**
|
|
1285
|
+
* @private
|
|
1286
|
+
* @param {Event} event
|
|
1287
|
+
*/
|
|
1288
|
+
function handleFilterKeyboardEvents(event) {;
|
|
1289
|
+
|
|
1290
|
+
const shiftKey = event?.["shiftKey"];
|
|
1291
|
+
|
|
1292
|
+
switch (event?.["code"]) {
|
|
1293
|
+
case "Tab":
|
|
1294
|
+
activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
|
|
1295
|
+
event.preventDefault();
|
|
1296
|
+
break;
|
|
1297
|
+
case "Escape":
|
|
1298
|
+
toggle.call(this);
|
|
1299
|
+
event.preventDefault();
|
|
1300
|
+
break;
|
|
1301
|
+
case "Tab" && shiftKey === true:
|
|
1302
|
+
case "ArrowUp":
|
|
1303
|
+
activateCurrentOption.call(this, FOCUS_DIRECTION_UP);
|
|
1304
|
+
event.preventDefault();
|
|
1305
|
+
break;
|
|
1306
|
+
case "Tab" && !shiftKey:
|
|
1307
|
+
case "ArrowDown":
|
|
1308
|
+
activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
|
|
1309
|
+
event.preventDefault();
|
|
1310
|
+
break;
|
|
1311
|
+
default:
|
|
1312
|
+
if (this.getOption("filter.mode") !== FILTER_MODE_REMOTE) {
|
|
1313
|
+
filterOptions.call(this);
|
|
1314
|
+
} else {
|
|
1315
|
+
filterFromRemote.call(this).catch((e) => {
|
|
1316
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* @private
|
|
1324
|
+
*/
|
|
1325
|
+
function filterFromRemote() {;
|
|
1326
|
+
|
|
1327
|
+
if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) {
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
const optionUrl = this.getOption("url");
|
|
1332
|
+
if (!optionUrl) {
|
|
1333
|
+
addAttributeToken(
|
|
1334
|
+
this,
|
|
1335
|
+
ATTRIBUTE_ERRORMESSAGE,
|
|
1336
|
+
"Missing URL for Remote Filter.",
|
|
1337
|
+
);
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
return new Processing(() => {
|
|
1342
|
+
const filterValue = encodeURI(
|
|
1343
|
+
this[inlineFilterElementSymbol].value.toLowerCase(),
|
|
1344
|
+
);
|
|
1345
|
+
let url = optionUrl;
|
|
1346
|
+
if (filterValue.length > 0) {
|
|
1347
|
+
url = new Formatter({ filter: filterValue }).format(optionUrl);
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
this
|
|
1351
|
+
.fetch(url)
|
|
1352
|
+
.then(() => {
|
|
1353
|
+
checkOptionState.call(this);
|
|
1354
|
+
})
|
|
1355
|
+
.catch((e) => {
|
|
1356
|
+
throw e;
|
|
1357
|
+
});
|
|
1358
|
+
}).run();
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
/**
|
|
1362
|
+
*
|
|
1363
|
+
* @param {Event} event
|
|
1364
|
+
* @private
|
|
1365
|
+
*/
|
|
1366
|
+
function handleOptionKeyboardEvents(event) {;
|
|
1367
|
+
|
|
1368
|
+
const shiftKey = event?.["shiftKey"];
|
|
1369
|
+
|
|
1370
|
+
switch (event?.["code"]) {
|
|
1371
|
+
case "Escape":
|
|
1372
|
+
toggle.call(this);
|
|
1373
|
+
event.preventDefault();
|
|
1374
|
+
break;
|
|
1375
|
+
case "Enter":
|
|
1376
|
+
case "Space":
|
|
1377
|
+
const path = event.composedPath();
|
|
1378
|
+
const element = path?.[0];
|
|
1379
|
+
|
|
1380
|
+
fireEvent(element.getElementsByTagName("input"), "click");
|
|
1381
|
+
event.preventDefault();
|
|
1382
|
+
break;
|
|
1383
|
+
|
|
1384
|
+
case "Tab" && shiftKey === true:
|
|
1385
|
+
case "ArrowUp":
|
|
1386
|
+
activateCurrentOption.call(this, FOCUS_DIRECTION_UP);
|
|
1387
|
+
event.preventDefault();
|
|
1388
|
+
break;
|
|
1389
|
+
|
|
1390
|
+
case "Tab" && !shiftKey:
|
|
1391
|
+
case "ArrowLeft":
|
|
1392
|
+
case "ArrowRight":
|
|
1393
|
+
// handled by tree select
|
|
1394
|
+
break;
|
|
1395
|
+
case "ArrowDown":
|
|
1396
|
+
activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN);
|
|
1397
|
+
event.preventDefault();
|
|
1398
|
+
break;
|
|
1399
|
+
default:
|
|
1400
|
+
const p = event.composedPath();
|
|
1401
|
+
if (p?.[0] instanceof HTMLInputElement) {
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
focusFilter.call(this);
|
|
1405
|
+
break;
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
/**
|
|
1410
|
+
* @private
|
|
1411
|
+
* @returns {string}
|
|
1412
|
+
*/
|
|
1413
|
+
function getFilterMode() {;
|
|
1414
|
+
|
|
1415
|
+
switch (this.getOption("filter.mode")) {
|
|
1416
|
+
case FILTER_MODE_OPTIONS:
|
|
1417
|
+
return FILTER_MODE_OPTIONS;
|
|
1418
|
+
case FILTER_MODE_REMOTE:
|
|
1419
|
+
return FILTER_MODE_REMOTE;
|
|
1420
|
+
default:
|
|
1421
|
+
return FILTER_MODE_DISABLED;
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
/**
|
|
1426
|
+
* @private
|
|
1427
|
+
*/
|
|
1428
|
+
function blurFilter() {;
|
|
1429
|
+
|
|
1430
|
+
if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) {
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
this[popperFilterContainerElementSymbol].classList.remove("active");
|
|
1439
|
+
this[popperFilterContainerElementSymbol].blur();
|
|
1440
|
+
|
|
1441
|
+
this[inlineFilterElementSymbol].classList.remove("active");
|
|
1442
|
+
this[inlineFilterElementSymbol].blur();
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
/**
|
|
1446
|
+
* @private
|
|
1447
|
+
* @param focusOptions
|
|
1448
|
+
*/
|
|
1449
|
+
function focusPopperFilter(focusOptions) {;
|
|
1450
|
+
|
|
1451
|
+
this[popperFilterContainerElementSymbol].classList.remove("d-none");
|
|
1452
|
+
this[popperFilterElementSymbol].classList.add("active");
|
|
1453
|
+
this[inlineFilterElementSymbol].classList.remove("active");
|
|
1454
|
+
this[inlineFilterElementSymbol].classList.add("d-none");
|
|
1455
|
+
|
|
1456
|
+
if (!(this[popperFilterElementSymbol] instanceof HTMLElement)) {
|
|
1457
|
+
addAttributeToken(
|
|
1458
|
+
this,
|
|
1459
|
+
ATTRIBUTE_ERRORMESSAGE,
|
|
1460
|
+
"Missing Popper Filter Element.",
|
|
1461
|
+
);
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// visibility is set to visible, because focus() does not work on invisible elements
|
|
1466
|
+
// and the class definition is assigned later in the processing
|
|
1467
|
+
setTimeout(() => {
|
|
1468
|
+
if (focusOptions === undefined || focusOptions === null) {
|
|
1469
|
+
this[popperFilterElementSymbol].focus();
|
|
1470
|
+
} else {
|
|
1471
|
+
this[popperFilterElementSymbol].focus(focusOptions);
|
|
1472
|
+
}
|
|
1473
|
+
}, 100);
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
/**
|
|
1477
|
+
* @private
|
|
1478
|
+
* @param focusOptions
|
|
1479
|
+
*/
|
|
1480
|
+
function focusInlineFilter(focusOptions) {;
|
|
1481
|
+
|
|
1482
|
+
const options = this.getOption("options");
|
|
1483
|
+
if (
|
|
1484
|
+
(!isArray(options) || options.length === 0) &&
|
|
1485
|
+
this.getOption("filter.mode") !== FILTER_MODE_REMOTE
|
|
1486
|
+
) {
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
this[popperFilterContainerElementSymbol].classList.add("d-none");
|
|
1491
|
+
this[inlineFilterElementSymbol].classList.add("active");
|
|
1492
|
+
this[inlineFilterElementSymbol].classList.remove("d-none");
|
|
1493
|
+
|
|
1494
|
+
// visibility is set to visible, because focus() does not work on invisible elements
|
|
1495
|
+
// and the class definition is assigned later in the processing
|
|
1496
|
+
setTimeout(() => {
|
|
1497
|
+
if (focusOptions === undefined || focusOptions === null) {
|
|
1498
|
+
this[inlineFilterElementSymbol].focus();
|
|
1499
|
+
} else {
|
|
1500
|
+
this[inlineFilterElementSymbol].focus(focusOptions);
|
|
1501
|
+
}
|
|
1502
|
+
}, 100);
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
/**
|
|
1506
|
+
* @private
|
|
1507
|
+
*/
|
|
1508
|
+
function focusFilter(focusOptions) {;
|
|
1509
|
+
|
|
1510
|
+
if (getFilterMode.call(this) === FILTER_MODE_DISABLED) {
|
|
1511
|
+
this[popperFilterContainerElementSymbol].classList.add("d-none");
|
|
1512
|
+
this[inlineFilterElementSymbol].classList.add("d-none");
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
if (this.getOption("filter.position") === FILTER_POSITION_INLINE) {
|
|
1517
|
+
return focusInlineFilter.call(this, focusOptions);
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
return focusPopperFilter.call(this, focusOptions);
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
/**
|
|
1524
|
+
* @private
|
|
1525
|
+
* @return {array}
|
|
1526
|
+
* @throws {Error} no shadow-root is defined
|
|
1527
|
+
* @throws {Error} unsupported type
|
|
1528
|
+
*/
|
|
1529
|
+
function gatherState() {;
|
|
1530
|
+
|
|
1531
|
+
const type = this.getOption("type");
|
|
1532
|
+
if (["radio", "checkbox"].indexOf(type) === -1) {
|
|
1533
|
+
throw new Error("unsupported type");
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
if (!this.shadowRoot) {
|
|
1537
|
+
throw new Error("no shadow-root is defined");
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
const selection = [];
|
|
1541
|
+
const elements = this.shadowRoot.querySelectorAll(
|
|
1542
|
+
`input[type=${type}]:checked`,
|
|
1543
|
+
);
|
|
1544
|
+
for (const e of elements) {
|
|
1545
|
+
selection.push({
|
|
1546
|
+
label: getSelectionLabel.call(this, e.value),
|
|
1547
|
+
value: e.value,
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
setSelection
|
|
1552
|
+
.call(this, selection)
|
|
1553
|
+
.then(() => {})
|
|
1554
|
+
.catch((e) => {
|
|
1555
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
|
|
1556
|
+
});
|
|
1557
|
+
|
|
1558
|
+
return this;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
/**
|
|
1562
|
+
* @private
|
|
1563
|
+
* @throws {Error} no shadow-root is defined
|
|
1564
|
+
* @throws {Error} unsupported type
|
|
1565
|
+
*/
|
|
1566
|
+
function clearSelection() {;
|
|
1567
|
+
|
|
1568
|
+
const type = this.getOption("type");
|
|
1569
|
+
if (["radio", "checkbox"].indexOf(type) === -1) {
|
|
1570
|
+
throw new Error("unsupported type");
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
if (!this.shadowRoot) {
|
|
1574
|
+
throw new Error("no shadow-root is defined");
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
setSelection
|
|
1578
|
+
.call(this, [])
|
|
1579
|
+
.then(() => {})
|
|
1580
|
+
.catch((e) => {
|
|
1581
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
|
|
1582
|
+
});
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
/**
|
|
1586
|
+
* @private
|
|
1587
|
+
*/
|
|
1588
|
+
function areOptionsAvailableAndInit() {;
|
|
1589
|
+
|
|
1590
|
+
// prevent multiple calls
|
|
1591
|
+
if (this[areOptionsAvailableAndInitSymbol] === undefined) {
|
|
1592
|
+
this[areOptionsAvailableAndInitSymbol] = 0;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
if (this[areOptionsAvailableAndInitSymbol] > 0) {
|
|
1596
|
+
this[areOptionsAvailableAndInitSymbol]--;
|
|
1597
|
+
return true;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
this[areOptionsAvailableAndInitSymbol]++;
|
|
1601
|
+
|
|
1602
|
+
const options = this.getOption("options");
|
|
1603
|
+
|
|
1604
|
+
if (
|
|
1605
|
+
options === undefined ||
|
|
1606
|
+
options === null ||
|
|
1607
|
+
(isArray(options) && options.length === 0)
|
|
1608
|
+
) {
|
|
1609
|
+
setStatusOrRemoveBadges.call(this, "empty");
|
|
1610
|
+
|
|
1611
|
+
hide.call(this);
|
|
1612
|
+
|
|
1613
|
+
this.setOption(
|
|
1614
|
+
"messages.control",
|
|
1615
|
+
this.getOption("labels.no-options-available"),
|
|
1616
|
+
);
|
|
1617
|
+
this.setOption("messages.summary", "");
|
|
1618
|
+
this.setOption("selection", []);
|
|
1619
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage);
|
|
1620
|
+
return false;
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
const selections = this.getOption("selection");
|
|
1624
|
+
if (
|
|
1625
|
+
selections === undefined ||
|
|
1626
|
+
selections === null ||
|
|
1627
|
+
selections.length === 0
|
|
1628
|
+
) {
|
|
1629
|
+
this.setOption(
|
|
1630
|
+
"messages.control",
|
|
1631
|
+
this.getOption("labels.select-an-option"),
|
|
1632
|
+
);
|
|
1633
|
+
} else {
|
|
1634
|
+
this.setOption("messages.control", "");
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
this.setOption("messages.summary", setSummaryAndControlText.call(this));
|
|
1638
|
+
|
|
1639
|
+
let updated = false;
|
|
1640
|
+
let valueCounter = 1;
|
|
1641
|
+
for (const option of options) {
|
|
1642
|
+
if (option?.visibility === undefined) {
|
|
1643
|
+
option.visibility = "visible";
|
|
1644
|
+
updated = true;
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
if (option?.value === undefined && option?.label === undefined) {
|
|
1648
|
+
option.value = `${valueCounter++}`;
|
|
1649
|
+
option.label = option.value;
|
|
1650
|
+
updated = true;
|
|
1651
|
+
continue;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
if (option?.value === undefined) {
|
|
1655
|
+
option.value = option.label;
|
|
1656
|
+
updated = true;
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
if (option?.label === undefined) {
|
|
1660
|
+
option.label = option.value;
|
|
1661
|
+
updated = true;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
if (updated) {
|
|
1666
|
+
this.setOption("options", options);
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
setStatusOrRemoveBadges.call(this, "status");
|
|
1670
|
+
|
|
1671
|
+
removeAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage);
|
|
1672
|
+
return true;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
/**
|
|
1676
|
+
* @private
|
|
1677
|
+
* @throws {Error} no shadow-root is defined
|
|
1678
|
+
*/
|
|
1679
|
+
function checkOptionState() {;
|
|
1680
|
+
|
|
1681
|
+
if (!this.shadowRoot) {
|
|
1682
|
+
throw new Error("no shadow-root is defined");
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
const elements = this.shadowRoot.querySelectorAll(
|
|
1686
|
+
`[${ATTRIBUTE_ROLE}=option] input`,
|
|
1687
|
+
);
|
|
1688
|
+
|
|
1689
|
+
let selection = this.getOption("selection");
|
|
1690
|
+
if (!isArray(selection)) {
|
|
1691
|
+
selection = [];
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
const checkedValues = selection.map((a) => {
|
|
1695
|
+
return a.value;
|
|
1696
|
+
});
|
|
1697
|
+
|
|
1698
|
+
for (const e of elements) {
|
|
1699
|
+
if (checkedValues.indexOf(e.value) !== -1) {
|
|
1700
|
+
if (e.checked !== true) e.checked = true;
|
|
1701
|
+
} else {
|
|
1702
|
+
if (e.checked !== false) e.checked = false;
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
/**
|
|
1708
|
+
* @private
|
|
1709
|
+
* @param {*} value
|
|
1710
|
+
* @return {Object}
|
|
1711
|
+
*/
|
|
1712
|
+
function convertValueToSelection(value) {;
|
|
1713
|
+
const selection = [];
|
|
1714
|
+
|
|
1715
|
+
if (isString(value)) {
|
|
1716
|
+
value = value
|
|
1717
|
+
.split(",")
|
|
1718
|
+
.map((a) => {
|
|
1719
|
+
return a.trim();
|
|
1720
|
+
})
|
|
1721
|
+
.filter((a) => {
|
|
1722
|
+
return a !== "";
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
if (isString(value) || isInteger(value)) {
|
|
1727
|
+
selection.push({
|
|
1728
|
+
label: getSelectionLabel.call(this, value),
|
|
1729
|
+
value: value,
|
|
1730
|
+
});
|
|
1731
|
+
} else if (isArray(value)) {
|
|
1732
|
+
for (const v of value) {
|
|
1733
|
+
selection.push({
|
|
1734
|
+
label: getSelectionLabel.call(this, v),
|
|
1735
|
+
value: v,
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
value = value.join(",");
|
|
1740
|
+
} else {
|
|
1741
|
+
throw new Error("unsupported type");
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
return {
|
|
1745
|
+
selection: selection,
|
|
1746
|
+
value: value,
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
/**
|
|
1751
|
+
* @private
|
|
1752
|
+
* @param {array} selection
|
|
1753
|
+
* @return {string}
|
|
1754
|
+
*/
|
|
1755
|
+
function convertSelectionToValue(selection) {;
|
|
1756
|
+
|
|
1757
|
+
const value = [];
|
|
1758
|
+
|
|
1759
|
+
if (isArray(selection)) {
|
|
1760
|
+
for (const obj of selection) {
|
|
1761
|
+
const v = obj?.["value"];
|
|
1762
|
+
if (v !== undefined) value.push(v);
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
if (value.length === 0) {
|
|
1767
|
+
return "";
|
|
1768
|
+
} else if (value.length === 1) {
|
|
1769
|
+
return value.pop();
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
return value.join(",");
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
/**
|
|
1776
|
+
* @private
|
|
1777
|
+
* @param {array} selection
|
|
1778
|
+
* @return {Promise}
|
|
1779
|
+
* @throws {Error} no shadow-root is defined
|
|
1780
|
+
*/
|
|
1781
|
+
function setSelection(selection) {;
|
|
1782
|
+
|
|
1783
|
+
if (isString(selection)) {
|
|
1784
|
+
const result = convertValueToSelection.call(this, selection);
|
|
1785
|
+
selection = result?.selection;
|
|
1786
|
+
} else if (selection === undefined) {
|
|
1787
|
+
selection = [];
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
this.setOption("selection", validateArray(selection));
|
|
1791
|
+
checkOptionState.call(this);
|
|
1792
|
+
|
|
1793
|
+
try {
|
|
1794
|
+
this?.setFormValue(this.value);
|
|
1795
|
+
} catch (e) {
|
|
1796
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1799
|
+
fireCustomEvent(this, "monster-selected", {
|
|
1800
|
+
selection,
|
|
1801
|
+
});
|
|
1802
|
+
|
|
1803
|
+
return new Processing(() => {
|
|
1804
|
+
const CLASSNAME = "selected";
|
|
1805
|
+
|
|
1806
|
+
if (!this.shadowRoot) {
|
|
1807
|
+
throw new Error("no shadow-root is defined");
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
const notSelected = this.shadowRoot.querySelectorAll(":not(:checked)");
|
|
1811
|
+
|
|
1812
|
+
if (notSelected) {
|
|
1813
|
+
notSelected.forEach((node) => {
|
|
1814
|
+
const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`);
|
|
1815
|
+
if (parent) {
|
|
1816
|
+
parent.classList.remove(CLASSNAME);
|
|
1817
|
+
}
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
|
|
1821
|
+
const selected = this.shadowRoot.querySelectorAll(":checked");
|
|
1822
|
+
if (selected) {
|
|
1823
|
+
selected.forEach((node) => {
|
|
1824
|
+
const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`);
|
|
1825
|
+
if (parent) {
|
|
1826
|
+
parent.classList.add(CLASSNAME);
|
|
1827
|
+
}
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
}).run();
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
/**
|
|
1834
|
+
* @private
|
|
1835
|
+
* @param {string} url
|
|
1836
|
+
* @return {Promise}
|
|
1837
|
+
* @throws {TypeError} the result cannot be parsed
|
|
1838
|
+
* @throws {TypeError} unsupported response
|
|
1839
|
+
*/
|
|
1840
|
+
function fetchData(url) {;
|
|
1841
|
+
|
|
1842
|
+
if (!url) url = this.getOption("url");
|
|
1843
|
+
if (!url) return Promise.resolve();
|
|
1844
|
+
|
|
1845
|
+
const fetchOptions = this.getOption("fetch", {});
|
|
1846
|
+
|
|
1847
|
+
setStatusOrRemoveBadges.call(this, "loading");
|
|
1848
|
+
url = new Formatter({ filter: this.getOption("filter.defaultValue") }).format(
|
|
1849
|
+
url,
|
|
1850
|
+
);
|
|
1851
|
+
|
|
1852
|
+
const global = getGlobal();
|
|
1853
|
+
return global
|
|
1854
|
+
.fetch(url, fetchOptions)
|
|
1855
|
+
.then((response) => {
|
|
1856
|
+
const contentType = response.headers.get("content-type");
|
|
1857
|
+
if (contentType && contentType.indexOf("application/json") !== -1) {
|
|
1858
|
+
return response.text();
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
throw new TypeError(`unsupported response ${contentType}`);
|
|
1862
|
+
})
|
|
1863
|
+
.then((text) => {
|
|
1864
|
+
try {
|
|
1865
|
+
return Promise.resolve(JSON.parse(String(text)));
|
|
1866
|
+
} catch (e) {
|
|
1867
|
+
throw new TypeError("the result cannot be parsed");
|
|
1868
|
+
}
|
|
1869
|
+
});
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
/**
|
|
1873
|
+
* @private
|
|
1874
|
+
*/
|
|
1875
|
+
function hide() {;
|
|
1876
|
+
|
|
1877
|
+
this[popperElementSymbol].style.display = "none";
|
|
1878
|
+
setStatusOrRemoveBadges.call(this, "status");
|
|
1879
|
+
removeAttributeToken(this[controlElementSymbol], "class", "open");
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
/**
|
|
1883
|
+
* @private
|
|
1884
|
+
*/
|
|
1885
|
+
function show() {;
|
|
1886
|
+
|
|
1887
|
+
if (this.getOption("disabled", undefined) === true) {
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
|
|
1892
|
+
return;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
focusFilter.call(this);
|
|
1896
|
+
const optionsAvailable = areOptionsAvailableAndInit.call(this);
|
|
1897
|
+
const remoteFilterFlag = this.getOption("filter.mode") === FILTER_MODE_REMOTE;
|
|
1898
|
+
|
|
1899
|
+
if (optionsAvailable === false && remoteFilterFlag !== true) {
|
|
1900
|
+
const loadOnOpenFlag = this.getOption("features.loadOnOpen");
|
|
1901
|
+
if (loadOnOpenFlag === true) {
|
|
1902
|
+
this.setOption("features.loadOnOpen", false);
|
|
1903
|
+
this.setOption("classes.statusOrRemoveBadge", "loading");
|
|
1904
|
+
this.fetch().then(() => {
|
|
1905
|
+
show.call(this);
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
return;
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
this[popperElementSymbol].style.visibility = "hidden";
|
|
1913
|
+
this[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK;
|
|
1914
|
+
setStatusOrRemoveBadges.call(this, "open");
|
|
1915
|
+
|
|
1916
|
+
addAttributeToken(this[controlElementSymbol], "class", "open");
|
|
1917
|
+
|
|
1918
|
+
new Processing(() => {
|
|
1919
|
+
calcAndSetOptionsDimension.call(this);
|
|
1920
|
+
focusFilter.call(this);
|
|
1921
|
+
this[popperElementSymbol].style.removeProperty("visibility");
|
|
1922
|
+
updatePopper.call(this);
|
|
1923
|
+
})
|
|
1924
|
+
.run()
|
|
1925
|
+
.catch((e) => {
|
|
1926
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
1927
|
+
});
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
/**
|
|
1931
|
+
* @private
|
|
1932
|
+
*/
|
|
1933
|
+
function toggle() {
|
|
1934
|
+
if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
|
|
1935
|
+
hide.call(this);
|
|
1936
|
+
} else {
|
|
1937
|
+
show.call(this);
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
/**
|
|
1942
|
+
* @private
|
|
1943
|
+
* @fires Monster.Components.Form.event:monster-selection-removed
|
|
1944
|
+
* @fires Monster.Components.Form.event:monster-selection-cleared
|
|
1945
|
+
*/
|
|
1946
|
+
function initEventhandler() {
|
|
1947
|
+
const self = this;
|
|
1948
|
+
|
|
1949
|
+
/**
|
|
1950
|
+
* @param {Event} event
|
|
1951
|
+
*/
|
|
1952
|
+
self[clearOptionEventHandler] = (event) => {
|
|
1953
|
+
const element = findTargetElementFromEvent(
|
|
1954
|
+
event,
|
|
1955
|
+
ATTRIBUTE_ROLE,
|
|
1956
|
+
"remove-badge",
|
|
1957
|
+
);
|
|
1958
|
+
if (element instanceof HTMLElement) {
|
|
1959
|
+
const badge = findClosestByAttribute(element, ATTRIBUTE_ROLE, "badge");
|
|
1960
|
+
if (badge instanceof HTMLElement) {
|
|
1961
|
+
const value = badge.getAttribute(`${ATTRIBUTE_PREFIX}value`);
|
|
1962
|
+
|
|
1963
|
+
let selection = self.getOption("selection");
|
|
1964
|
+
selection = selection.filter((b) => {
|
|
1965
|
+
return value !== b.value;
|
|
1966
|
+
});
|
|
1967
|
+
|
|
1968
|
+
setSelection
|
|
1969
|
+
.call(self, selection)
|
|
1970
|
+
.then(() => {
|
|
1971
|
+
fireCustomEvent(self, "monster-selection-removed", {
|
|
1972
|
+
value,
|
|
1973
|
+
});
|
|
1974
|
+
})
|
|
1975
|
+
.catch((e) => {
|
|
1976
|
+
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
};
|
|
1981
|
+
|
|
1982
|
+
/**
|
|
1983
|
+
* @param {Event} event
|
|
1984
|
+
*/
|
|
1985
|
+
self[closeEventHandler] = (event) => {
|
|
1986
|
+
const path = event.composedPath();
|
|
1987
|
+
|
|
1988
|
+
for (const [, element] of Object.entries(path)) {
|
|
1989
|
+
if (element === self) {
|
|
1990
|
+
return;
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
hide.call(self);
|
|
1994
|
+
};
|
|
1995
|
+
|
|
1996
|
+
/**
|
|
1997
|
+
* @param {Event} event
|
|
1998
|
+
*/
|
|
1999
|
+
self[inputEventHandler] = (event) => {
|
|
2000
|
+
const path = event.composedPath();
|
|
2001
|
+
const element = path?.[0];
|
|
2002
|
+
|
|
2003
|
+
if (element instanceof HTMLElement) {
|
|
2004
|
+
if (
|
|
2005
|
+
element.hasAttribute(ATTRIBUTE_ROLE) &&
|
|
2006
|
+
element.getAttribute(ATTRIBUTE_ROLE) === "option-control"
|
|
2007
|
+
) {
|
|
2008
|
+
fireCustomEvent(self, "monster-change", {
|
|
2009
|
+
type: event.type,
|
|
2010
|
+
value: element.value,
|
|
2011
|
+
checked: element.checked,
|
|
2012
|
+
});
|
|
2013
|
+
} else if (
|
|
2014
|
+
element.hasAttribute(ATTRIBUTE_ROLE) &&
|
|
2015
|
+
element.getAttribute(ATTRIBUTE_ROLE) === "filter"
|
|
2016
|
+
) {
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
};
|
|
2020
|
+
|
|
2021
|
+
/**
|
|
2022
|
+
* @param {Event} event
|
|
2023
|
+
*/
|
|
2024
|
+
self[changeEventHandler] = (event) => {
|
|
2025
|
+
gatherState.call(self);
|
|
2026
|
+
fireCustomEvent(self, "monster-changed", event?.detail);
|
|
2027
|
+
};
|
|
2028
|
+
|
|
2029
|
+
self[keyEventHandler] = (event) => {
|
|
2030
|
+
const path = event.composedPath();
|
|
2031
|
+
const element = path.shift();
|
|
2032
|
+
|
|
2033
|
+
let role;
|
|
2034
|
+
|
|
2035
|
+
if (element instanceof HTMLElement) {
|
|
2036
|
+
if (element.hasAttribute(ATTRIBUTE_ROLE)) {
|
|
2037
|
+
role = element.getAttribute(ATTRIBUTE_ROLE);
|
|
2038
|
+
} else if (element === this) {
|
|
2039
|
+
show.call(this);
|
|
2040
|
+
// focusFilter.call(self);
|
|
2041
|
+
} else {
|
|
2042
|
+
const e = element.closest(`[${ATTRIBUTE_ROLE}]`);
|
|
2043
|
+
if (e instanceof HTMLElement && e.hasAttribute(ATTRIBUTE_ROLE)) {
|
|
2044
|
+
role = e.getAttribute(ATTRIBUTE_ROLE);
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
} else {
|
|
2048
|
+
return;
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
switch (role) {
|
|
2052
|
+
case "filter":
|
|
2053
|
+
handleFilterKeyboardEvents.call(self, event);
|
|
2054
|
+
break;
|
|
2055
|
+
case "option-label":
|
|
2056
|
+
case "option-control":
|
|
2057
|
+
case "option":
|
|
2058
|
+
handleOptionKeyboardEvents.call(self, event);
|
|
2059
|
+
break;
|
|
2060
|
+
case "control":
|
|
2061
|
+
case "toggle":
|
|
2062
|
+
handleToggleKeyboardEvents.call(self, event);
|
|
2063
|
+
break;
|
|
2064
|
+
}
|
|
2065
|
+
};
|
|
2066
|
+
|
|
2067
|
+
const types = self.getOption("toggleEventType", ["click"]);
|
|
2068
|
+
|
|
2069
|
+
for (const [, type] of Object.entries(types)) {
|
|
2070
|
+
self[controlElementSymbol]
|
|
2071
|
+
.querySelector(`[${ATTRIBUTE_ROLE}="container"]`)
|
|
2072
|
+
.addEventListener(type, function (event) {
|
|
2073
|
+
const element = findTargetElementFromEvent(
|
|
2074
|
+
event,
|
|
2075
|
+
ATTRIBUTE_ROLE,
|
|
2076
|
+
"remove-badge",
|
|
2077
|
+
);
|
|
2078
|
+
if (element instanceof HTMLElement) {
|
|
2079
|
+
return;
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
toggle.call(self);
|
|
2083
|
+
});
|
|
2084
|
+
|
|
2085
|
+
self[controlElementSymbol]
|
|
2086
|
+
.querySelector(`[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`)
|
|
2087
|
+
.addEventListener(type, function (event) {
|
|
2088
|
+
if (self.getOption("disabled", undefined) === true) {
|
|
2089
|
+
return;
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
const path = event.composedPath();
|
|
2093
|
+
const element = path?.[0];
|
|
2094
|
+
if (element instanceof HTMLElement) {
|
|
2095
|
+
const control = element.closest(
|
|
2096
|
+
`[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`,
|
|
2097
|
+
);
|
|
2098
|
+
if (control instanceof HTMLElement) {
|
|
2099
|
+
if (control.classList.contains("clear")) {
|
|
2100
|
+
clearSelection.call(self);
|
|
2101
|
+
|
|
2102
|
+
fireCustomEvent(self, "monster-selection-cleared", {});
|
|
2103
|
+
} else {
|
|
2104
|
+
const element = findTargetElementFromEvent(
|
|
2105
|
+
event,
|
|
2106
|
+
ATTRIBUTE_ROLE,
|
|
2107
|
+
"remove-badge",
|
|
2108
|
+
);
|
|
2109
|
+
if (element instanceof HTMLElement) {
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
toggle.call(self);
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
});
|
|
2118
|
+
|
|
2119
|
+
// badge, selection
|
|
2120
|
+
self.addEventListener(type, self[clearOptionEventHandler]);
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
self.addEventListener("monster-change", self[changeEventHandler]);
|
|
2124
|
+
self.addEventListener("input", self[inputEventHandler]);
|
|
2125
|
+
self.addEventListener("keydown", self[keyEventHandler]);
|
|
2126
|
+
|
|
2127
|
+
return self;
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
/**
|
|
2131
|
+
* @private
|
|
2132
|
+
* @return {Select}
|
|
2133
|
+
*/
|
|
2134
|
+
function setStatusOrRemoveBadges(suggestion) {;
|
|
2135
|
+
setTimeout(() => {
|
|
2136
|
+
const selection = this.getOption("selection");
|
|
2137
|
+
const clearAllFlag =
|
|
2138
|
+
isArray(selection) &&
|
|
2139
|
+
selection.length > 0 &&
|
|
2140
|
+
this.getOption("features.clearAll") === true;
|
|
2141
|
+
|
|
2142
|
+
if (clearAllFlag) {
|
|
2143
|
+
//this[statusOrRemoveBadgesElementSymbol].classList.remove("status");
|
|
2144
|
+
//this[statusOrRemoveBadgesElementSymbol].classList.add("clear");
|
|
2145
|
+
this.setOption("classes.statusOrRemoveBadge", "clear");
|
|
2146
|
+
return;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
if (suggestion === "loading") {
|
|
2150
|
+
this.setOption("classes.statusOrRemoveBadge", "loading");
|
|
2151
|
+
return;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
if (this[controlElementSymbol].classList.contains("open")) {
|
|
2155
|
+
this.setOption("classes.statusOrRemoveBadge", "open");
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
const options = this.getOption("options");
|
|
2160
|
+
if (
|
|
2161
|
+
options === undefined ||
|
|
2162
|
+
options === null ||
|
|
2163
|
+
(isArray(options) && options.length === 0)
|
|
2164
|
+
) {
|
|
2165
|
+
this.setOption("classes.statusOrRemoveBadge", "empty");
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
if (suggestion) {
|
|
2170
|
+
this.setOption("classes.statusOrRemoveBadge", suggestion);
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
}, 2);
|
|
2174
|
+
}
|
|
2175
|
+
|
|
2176
|
+
/**
|
|
2177
|
+
* @private
|
|
2178
|
+
* @return {Select}
|
|
2179
|
+
* @throws {Error} no shadow-root is defined
|
|
2180
|
+
*/
|
|
2181
|
+
function initControlReferences() {;
|
|
2182
|
+
|
|
2183
|
+
if (!this.shadowRoot) {
|
|
2184
|
+
throw new Error("no shadow-root is defined");
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
this[controlElementSymbol] = this.shadowRoot.querySelector(
|
|
2188
|
+
`[${ATTRIBUTE_ROLE}=control]`,
|
|
2189
|
+
);
|
|
2190
|
+
this[selectionElementSymbol] = this.shadowRoot.querySelector(
|
|
2191
|
+
`[${ATTRIBUTE_ROLE}=selection]`,
|
|
2192
|
+
);
|
|
2193
|
+
this[containerElementSymbol] = this.shadowRoot.querySelector(
|
|
2194
|
+
`[${ATTRIBUTE_ROLE}=container]`,
|
|
2195
|
+
);
|
|
2196
|
+
this[popperElementSymbol] = this.shadowRoot.querySelector(
|
|
2197
|
+
`[${ATTRIBUTE_ROLE}=popper]`,
|
|
2198
|
+
);
|
|
2199
|
+
this[inlineFilterElementSymbol] = this.shadowRoot.querySelector(
|
|
2200
|
+
`[${ATTRIBUTE_ROLE}=filter][name="inline-filter"]`,
|
|
2201
|
+
);
|
|
2202
|
+
this[popperFilterElementSymbol] = this.shadowRoot.querySelector(
|
|
2203
|
+
`[${ATTRIBUTE_ROLE}=filter][name="popper-filter"]`,
|
|
2204
|
+
);
|
|
2205
|
+
this[popperFilterContainerElementSymbol] =
|
|
2206
|
+
this[popperFilterElementSymbol].parentElement;
|
|
2207
|
+
this[optionsElementSymbol] = this.shadowRoot.querySelector(
|
|
2208
|
+
`[${ATTRIBUTE_ROLE}=options]`,
|
|
2209
|
+
);
|
|
2210
|
+
this[noOptionsAvailableElementSymbol] = this.shadowRoot.querySelector(
|
|
2211
|
+
`[${ATTRIBUTE_ROLE}="no-options"]`,
|
|
2212
|
+
);
|
|
2213
|
+
this[statusOrRemoveBadgesElementSymbol] = this.shadowRoot.querySelector(
|
|
2214
|
+
`[${ATTRIBUTE_ROLE}=status-or-remove-badges]`,
|
|
2215
|
+
);
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
/**
|
|
2219
|
+
* @private
|
|
2220
|
+
*/
|
|
2221
|
+
function updatePopper() {;
|
|
2222
|
+
|
|
2223
|
+
if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) {
|
|
2224
|
+
return;
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
if (this.getOption("disabled", false) === true) {
|
|
2228
|
+
return;
|
|
2229
|
+
}
|
|
2230
|
+
|
|
2231
|
+
new Processing(() => {
|
|
2232
|
+
calcAndSetOptionsDimension.call(this);
|
|
2233
|
+
positionPopper.call(
|
|
2234
|
+
this,
|
|
2235
|
+
this[controlElementSymbol],
|
|
2236
|
+
this[popperElementSymbol],
|
|
2237
|
+
this.getOption("popper", {}),
|
|
2238
|
+
);
|
|
2239
|
+
}).run();
|
|
2240
|
+
|
|
2241
|
+
return this;
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
/**
|
|
2245
|
+
* @private
|
|
2246
|
+
* @return {string}
|
|
2247
|
+
*/
|
|
2248
|
+
function getTemplate() {
|
|
2249
|
+
// language=HTML
|
|
2250
|
+
return `
|
|
2251
|
+
<template id="options">
|
|
2252
|
+
<div data-monster-role="option" tabindex="-1"
|
|
2253
|
+
data-monster-attributes="
|
|
2254
|
+
data-monster-filtered path:options.filtered,
|
|
2255
|
+
data-monster-visibility path:options.visibility">
|
|
2256
|
+
<label part="option" role="option">
|
|
2257
|
+
<input data-monster-role="option-control"
|
|
2258
|
+
data-monster-attributes="
|
|
2259
|
+
type path:type,
|
|
2260
|
+
role path:role,
|
|
2261
|
+
value path:options | index:value,
|
|
2262
|
+
name path:name,
|
|
2263
|
+
part path:type | prefix:option- | suffix: form,
|
|
2264
|
+
class path:options.class
|
|
2265
|
+
" tabindex="-1">
|
|
2266
|
+
<div data-monster-replace="path:options | index:label" part="option-label"></div>
|
|
2267
|
+
</label>
|
|
2268
|
+
</div>
|
|
2269
|
+
</template>
|
|
2270
|
+
|
|
2271
|
+
<template id="selection">
|
|
2272
|
+
<div data-monster-role="badge"
|
|
2273
|
+
part="badge"
|
|
2274
|
+
data-monster-attributes="
|
|
2275
|
+
data-monster-value path:selection | index:value,
|
|
2276
|
+
class path:classes | index:badge,
|
|
2277
|
+
part path:type | suffix:-option | prefix: form-" tabindex="-1">
|
|
2278
|
+
<div data-monster-replace="path:selection | index:label" part="badge-label"
|
|
2279
|
+
data-monster-role="badge-label"></div>
|
|
2280
|
+
<div part="remove-badge" data-monster-select-this
|
|
2281
|
+
data-monster-attributes="class path:features.clear | ?::hidden "
|
|
2282
|
+
data-monster-role="remove-badge" tabindex="-1"></div>
|
|
2283
|
+
</div>
|
|
2284
|
+
</template>
|
|
2285
|
+
|
|
2286
|
+
<slot class="hidden"></slot>
|
|
2287
|
+
|
|
2288
|
+
<div data-monster-role="control" part="control" tabindex="0">
|
|
2289
|
+
<div data-monster-role="container">
|
|
2290
|
+
\${selected}
|
|
2291
|
+
</div>
|
|
2292
|
+
|
|
2293
|
+
<div data-monster-role="popper" part="popper" tabindex="-1" class="monster-color-primary-1">
|
|
2294
|
+
<div class="option-filter-control" role="search">
|
|
2295
|
+
<input type="text" role="searchbox"
|
|
2296
|
+
part="popper-filter" name="popper-filter"
|
|
2297
|
+
data-monster-role="filter"
|
|
2298
|
+
autocomplete="off"
|
|
2299
|
+
tabindex="0">
|
|
2300
|
+
</div>
|
|
2301
|
+
<div part="content" class="flex" data-monster-replace="path:content">
|
|
2302
|
+
<div part="options" data-monster-role="options" data-monster-insert="options path:options"
|
|
2303
|
+
tabindex="-1"></div>
|
|
2304
|
+
</div>
|
|
2305
|
+
<div part="no-options" data-monster-role="no-options"
|
|
2306
|
+
data-monster-replace="path:messages.emptyOptions"></div>
|
|
2307
|
+
</div>
|
|
2308
|
+
<div part="status-or-remove-badges" data-monster-role="status-or-remove-badges"
|
|
2309
|
+
data-monster-attributes="class path:classes.statusOrRemoveBadge | suffix:\\ status-or-remove-badges"></div>
|
|
2310
|
+
</div>
|
|
2311
|
+
`;
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
registerCustomElement(Select);
|