diff --git a/nix/config/release.nix b/nix/config/release.nix index 71fe64302851b3baa6af242377d27f2169dfb234..8156c964caece437ff540c6bb2d0e68782c8db3c 100644 --- a/nix/config/release.nix +++ b/nix/config/release.nix @@ -3,4 +3,4 @@ commit = "31625721077f93eed808f65c106cc0dea9dade40"; name = "Monster"; mnemonic = "monster"; -} \ No newline at end of file +} diff --git a/nix/scripts/release.nix b/nix/scripts/release.nix index 448def3c36d06fe8176f46526d1842b83d78f0c8..267ab65358c3aa20a7ae2c3e19f1de2444b0d013 100644 --- a/nix/scripts/release.nix +++ b/nix/scripts/release.nix @@ -9,86 +9,86 @@ in pkgs'.writeShellScriptBin "release" '' - source ${pkgs'.common}/bin/common - ${bashFktScript} - - echo_header "Release " - - if [ -z "$CI_REPOSITORY_URL" ]; then - echo_fail "Error: CI_REPOSITORY_URL environment variable is not set." - exit 1 - fi - - if [ -z "$CI_PROJECT_DIR" ]; then - echo_fail "Error: CI_PROJECT_DIR environment variable is not set." - exit 1 - fi - - cd $CI_PROJECT_DIR || exit 1 - - echo_step "Set git remote url to https://pad:secret@''${CI_REPOSITORY_URL#*@}" - ${pkgs'.git}/bin/git remote set-url origin https://pad:''${GITLAB_TOKEN}@''${CI_REPOSITORY_URL#*@} - - ${pkgs'.git}/bin/git fetch --all --tags --unshallow - ${pkgs'.git}/bin/git reset --hard origin/master - ${pkgs'.git}/bin/git clean -fd - ${pkgs'.git}/bin/git checkout $CI_COMMIT_REF_NAME - ${pkgs'.git}/bin/git pull origin $CI_COMMIT_REF_NAME - - if ! ${pkgs'.git}/bin/git --no-pager log --decorate=short --pretty=oneline -n 10 - then - echo_fail "Error: Could not get git log." - exit 1 - fi - - ${pkgs'.git}/bin/git fetch --prune --prune-tags - - echo_step "Bumping version" - gitVersion=$(${pkgs'.version}/bin/version predict --exit-code-if-no-bump) - if [ -z "$gitVersion" ]; then - echo_ok "There is no version bump." - echo_ok "done" - exit 0 - fi - - echo_step "Write project version" - ### marker - - export VERSION=$gitVersion - export COMMIT="$CI_COMMIT_SHA" - export NAME=$(basename $(pwd) | sed 's/./\U&/' | sed 's/-//g') - export MNEMONIC=$(echo $NAME | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]//g') - ${pkgs'.envsubst}/bin/envsubst < ./nix/config/release.nix.template > ./nix/config/release.nix - - if ! ${pkgs'.nodejs_20}/bin/npm version "$gitVersion" --no-git-tag-version --allow-same-version 2>/dev/null; then - echo_fail "Error: Could not write project version." - exit 1 - fi - - if ${pkgs'.git}/bin/git tag -l | grep -q "$gitVersion"; then - echo_step "Tag $gitVersion existiert bereits. Lösche und setze den Tag neu." - ${pkgs'.git}/bin/git tag -d "$gitVersion" - ${pkgs'.git}/bin/git push --push-option=ci.skip origin --delete "$gitVersion" - fi - - ${pkgs'.git}/bin/git tag -a "$gitVersion" -m"chore: bump version to $gitVersion" - ${updateChangelogScript}/bin/update-changelog - cd $CI_PROJECT_DIR || exit 1 - - if ! ${pkgs'.git}/bin/git tag -d "$gitVersion" 2>/dev/null; then - echo_fail "Error: Could not delete git tag $gitVersion." - exit 1 - fi - - ${pkgs'.git}/bin/git commit -m "chore: release $gitVersion" CHANGELOG.md ./nix/config/release.nix package.json - - ${pkgs'.git}/bin/git tag -a "$gitVersion" -m"chore: bump version to $gitVersion" - ${pkgs'.git}/bin/git --no-pager log --decorate=short --pretty=oneline -n 5 - - if ! ${pkgs'.git}/bin/git push --push-option=ci.variable="DEPLOY_VERSION=$gitVersion" origin "$CI_COMMIT_REF_NAME" --tags ; then - echo_fail "Error: Could not push git tag $gitVersion." - exit 1 - fi + source ${pkgs'.common}/bin/common + ${bashFktScript} + echo_header "Release " + + if [ -z "$CI_REPOSITORY_URL" ]; then + echo_fail "Error: CI_REPOSITORY_URL environment variable is not set." + exit 1 + fi + + if [ -z "$CI_PROJECT_DIR" ]; then + echo_fail "Error: CI_PROJECT_DIR environment variable is not set." + exit 1 + fi + + cd $CI_PROJECT_DIR || exit 1 + + echo_step "Set git remote url to https://pad:secret@''${CI_REPOSITORY_URL#*@}" + ${pkgs'.git}/bin/git remote set-url origin https://pad:''${GITLAB_TOKEN}@''${CI_REPOSITORY_URL#*@} + + ${pkgs'.git}/bin/git fetch --all --tags --unshallow + ${pkgs'.git}/bin/git reset --hard origin/master + ${pkgs'.git}/bin/git clean -fd + ${pkgs'.git}/bin/git checkout $CI_COMMIT_REF_NAME + ${pkgs'.git}/bin/git pull origin $CI_COMMIT_REF_NAME + + if ! ${pkgs'.git}/bin/git --no-pager log --decorate=short --pretty=oneline -n 10 + then + echo_fail "Error: Could not get git log." + exit 1 + fi + + ${pkgs'.git}/bin/git fetch --prune --prune-tags + + echo_step "Bumping version" + gitVersion=$(${pkgs'.version}/bin/version predict --exit-code-if-no-bump) + if [ -z "$gitVersion" ]; then + echo_ok "There is no version bump." echo_ok "done" + exit 0 + fi + + echo_step "Write project version" + ### marker + + export VERSION=$gitVersion + export COMMIT="$CI_COMMIT_SHA" + export NAME=$(basename $(pwd) | sed 's/./\U&/' | sed 's/-//g') + export MNEMONIC=$(echo $NAME | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]//g') + ${pkgs'.envsubst}/bin/envsubst < ./nix/config/release.nix.template > ./nix/config/release.nix + + if ! ${pkgs'.nodejs_20}/bin/npm version "$gitVersion" --no-git-tag-version --allow-same-version 2>/dev/null; then + echo_fail "Error: Could not write project version." + exit 1 + fi + + if ${pkgs'.git}/bin/git tag -l | grep -q "$gitVersion"; then + echo_step "Tag $gitVersion existiert bereits. Lösche und setze den Tag neu." + ${pkgs'.git}/bin/git tag -d "$gitVersion" + ${pkgs'.git}/bin/git push --push-option=ci.skip origin --delete "$gitVersion" + fi + + ${pkgs'.git}/bin/git tag -a "$gitVersion" -m"chore: bump version to $gitVersion" + ${updateChangelogScript}/bin/update-changelog + cd $CI_PROJECT_DIR || exit 1 + + if ! ${pkgs'.git}/bin/git tag -d "$gitVersion" 2>/dev/null; then + echo_fail "Error: Could not delete git tag $gitVersion." + exit 1 + fi + + ${pkgs'.git}/bin/git commit -m "chore: release $gitVersion" CHANGELOG.md ./nix/config/release.nix package.json + + ${pkgs'.git}/bin/git tag -a "$gitVersion" -m"chore: bump version to $gitVersion" + ${pkgs'.git}/bin/git --no-pager log --decorate=short --pretty=oneline -n 5 + + if ! ${pkgs'.git}/bin/git push --push-option=ci.variable="DEPLOY_VERSION=$gitVersion" origin "$CI_COMMIT_REF_NAME" --tags ; then + echo_fail "Error: Could not push git tag $gitVersion." + exit 1 + fi + + echo_ok "done" '' diff --git a/source/components/content/copy.mjs b/source/components/content/copy.mjs index d4916d647da7f97ae41fccc63b20e62694d5182f..0a78f8c35bba99257bc22c2176be4c439c17e50a 100644 --- a/source/components/content/copy.mjs +++ b/source/components/content/copy.mjs @@ -10,25 +10,28 @@ * For more information about purchasing a commercial license, please contact schukai GmbH. */ -import {instanceSymbol} from "../../constants.mjs"; -import {addAttributeToken, removeAttributeToken} from "../../dom/attributes.mjs"; +import { instanceSymbol } from "../../constants.mjs"; import { - ATTRIBUTE_ERRORMESSAGE, - ATTRIBUTE_ROLE, + addAttributeToken, + removeAttributeToken, +} from "../../dom/attributes.mjs"; +import { + ATTRIBUTE_ERRORMESSAGE, + ATTRIBUTE_ROLE, } from "../../dom/constants.mjs"; -import {CustomElement, getSlottedElements} from "../../dom/customelement.mjs"; +import { CustomElement, getSlottedElements } from "../../dom/customelement.mjs"; import { - assembleMethodSymbol, - registerCustomElement, + assembleMethodSymbol, + registerCustomElement, } from "../../dom/customelement.mjs"; -import {getDocument} from "../../dom/util.mjs"; -import {STYLE_DISPLAY_MODE_BLOCK} from "../form/constants.mjs"; -import {CopyStyleSheet} from "./stylesheet/copy.mjs"; -import {fireCustomEvent} from "../../dom/events.mjs"; +import { getDocument } from "../../dom/util.mjs"; +import { STYLE_DISPLAY_MODE_BLOCK } from "../form/constants.mjs"; +import { CopyStyleSheet } from "./stylesheet/copy.mjs"; +import { fireCustomEvent } from "../../dom/events.mjs"; import { positionPopper } from "../form/util/floating-ui.mjs"; import { DeadMansSwitch } from "../../util/deadmansswitch.mjs"; -export {Copy}; +export { Copy }; /** * @private @@ -36,7 +39,6 @@ export {Copy}; */ const timerCallbackSymbol = Symbol("timerCallback"); - /** * @private * @type {symbol} @@ -81,246 +83,242 @@ const resizeObserverSymbol = Symbol("resizeObserver"); * @summary A beautiful Copy that can make your life easier and also looks good. */ class Copy extends CustomElement { - /** - * This method is called by the `instanceof` operator. - * @returns {symbol} - */ - static get [instanceSymbol]() { - return Symbol.for("@schukai/monster/components/content/copy@@instance"); - } - - /** - * - * @return {Components.Content.Copy - */ - [assembleMethodSymbol]() { - super[assembleMethodSymbol](); - initControlReferences.call(this); - initEventHandler.call(this); - return this; - } - - - /** - * This method is called when the element is connected to the dom. - * - * @return {void} - */ - connectedCallback() { - super.connectedCallback(); - - const document = getDocument(); - - for (const [, type] of Object.entries(["click", "touch"])) { - // close on outside ui-events - document.addEventListener(type, this[closeEventHandler]); - } - - updatePopper.call(this); - attachResizeObserver.call(this); - } - - - /** - * This method is called when the element is disconnected from the dom. - * - * @return {void} - */ - disconnectedCallback() { - super.disconnectedCallback(); - - // close on outside ui-events - for (const [, type] of Object.entries(["click", "touch"])) { - document.removeEventListener(type, this[closeEventHandler]); - } - - disconnectResizeObserver.call(this); - } - - /** - * To set the options via the HTML Tag, the attribute `data-monster-options` must be used. - * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} - * - * The individual configuration values can be found in the table. - * - * @property {Object} templates Template definitions - * @property {string} templates.main Main template - * @property {Object} actions Callbacks - * @property {string} actions.click="throw Error" Callback when clicked - * @property {Object} features Features - * @property {boolean} features.stripTags=true Strip tags from the copied text - * @property {boolean} features.preventOpenEventSent=false Prevent open event from being sent - * @property {Object} popper Popper configuration - * @property {string} popper.placement="top" Popper placement - * @property {string[]} popper.middleware=["autoPlacement", "shift", "offset:15", "arrow"] Popper middleware - * @property {boolean} disabled=false Disabled state - */ - get defaults() { - return Object.assign({}, super.defaults, { - templates: { - main: getTemplate(), - }, - disabled: false, - features: { - stripTags: true, - preventOpenEventSent: false, - }, - popper: { - placement: "top", - middleware: ["autoPlacement", "shift", "offset:15", "arrow"], - }, - }); - } - - /** - * @return {string} - */ - static getTag() { - return "monster-copy"; - } - - /** - * @return {CSSStyleSheet[]} - */ - static getCSSStyleSheet() { - return [CopyStyleSheet]; - } - - /** - * With this method, you can show the popper. - * - * @return {Copy} - */ - showDialog() { - show.call(this); - return this; - } - - /** - * With this method, you can hide the popper. - * - * @return {Copy} - */ - hideDialog() { - hide.call(this); - return this; - } - - /** - * With this method, you can toggle the popper. - * - * @return {Copy} - */ - toggleDialog() { - if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) { - this.hideDialog(); - } else { - this.showDialog(); - } - return this; - } - - + /** + * This method is called by the `instanceof` operator. + * @returns {symbol} + */ + static get [instanceSymbol]() { + return Symbol.for("@schukai/monster/components/content/copy@@instance"); + } + + /** + * + * @return {Components.Content.Copy + */ + [assembleMethodSymbol]() { + super[assembleMethodSymbol](); + initControlReferences.call(this); + initEventHandler.call(this); + return this; + } + + /** + * This method is called when the element is connected to the dom. + * + * @return {void} + */ + connectedCallback() { + super.connectedCallback(); + + const document = getDocument(); + + for (const [, type] of Object.entries(["click", "touch"])) { + // close on outside ui-events + document.addEventListener(type, this[closeEventHandler]); + } + + updatePopper.call(this); + attachResizeObserver.call(this); + } + + /** + * This method is called when the element is disconnected from the dom. + * + * @return {void} + */ + disconnectedCallback() { + super.disconnectedCallback(); + + // close on outside ui-events + for (const [, type] of Object.entries(["click", "touch"])) { + document.removeEventListener(type, this[closeEventHandler]); + } + + disconnectResizeObserver.call(this); + } + + /** + * To set the options via the HTML Tag, the attribute `data-monster-options` must be used. + * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} + * + * The individual configuration values can be found in the table. + * + * @property {Object} templates Template definitions + * @property {string} templates.main Main template + * @property {Object} actions Callbacks + * @property {string} actions.click="throw Error" Callback when clicked + * @property {Object} features Features + * @property {boolean} features.stripTags=true Strip tags from the copied text + * @property {boolean} features.preventOpenEventSent=false Prevent open event from being sent + * @property {Object} popper Popper configuration + * @property {string} popper.placement="top" Popper placement + * @property {string[]} popper.middleware=["autoPlacement", "shift", "offset:15", "arrow"] Popper middleware + * @property {boolean} disabled=false Disabled state + */ + get defaults() { + return Object.assign({}, super.defaults, { + templates: { + main: getTemplate(), + }, + disabled: false, + features: { + stripTags: true, + preventOpenEventSent: false, + }, + popper: { + placement: "top", + middleware: ["autoPlacement", "shift", "offset:15", "arrow"], + }, + }); + } + + /** + * @return {string} + */ + static getTag() { + return "monster-copy"; + } + + /** + * @return {CSSStyleSheet[]} + */ + static getCSSStyleSheet() { + return [CopyStyleSheet]; + } + + /** + * With this method, you can show the popper. + * + * @return {Copy} + */ + showDialog() { + show.call(this); + return this; + } + + /** + * With this method, you can hide the popper. + * + * @return {Copy} + */ + hideDialog() { + hide.call(this); + return this; + } + + /** + * With this method, you can toggle the popper. + * + * @return {Copy} + */ + toggleDialog() { + if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) { + this.hideDialog(); + } else { + this.showDialog(); + } + return this; + } } /** * @private */ function attachResizeObserver() { - // against flickering - this[resizeObserverSymbol] = new ResizeObserver((entries) => { - if (this[timerCallbackSymbol] instanceof DeadMansSwitch) { - try { - this[timerCallbackSymbol].touch(); - return; - } catch (e) { - delete this[timerCallbackSymbol]; - } - } - - this[timerCallbackSymbol] = new DeadMansSwitch(200, () => { - updatePopper.call(this); - }); - }); - - this[resizeObserverSymbol].observe(this.parentElement); + // against flickering + this[resizeObserverSymbol] = new ResizeObserver((entries) => { + if (this[timerCallbackSymbol] instanceof DeadMansSwitch) { + try { + this[timerCallbackSymbol].touch(); + return; + } catch (e) { + delete this[timerCallbackSymbol]; + } + } + + this[timerCallbackSymbol] = new DeadMansSwitch(200, () => { + updatePopper.call(this); + }); + }); + + this[resizeObserverSymbol].observe(this.parentElement); } function disconnectResizeObserver() { - if (this[resizeObserverSymbol] instanceof ResizeObserver) { - this[resizeObserverSymbol].disconnect(); - } + if (this[resizeObserverSymbol] instanceof ResizeObserver) { + this[resizeObserverSymbol].disconnect(); + } } /** * @private */ function hide() { - const self = this; + const self = this; - fireCustomEvent(self, "monster-popper-hide", { - self, - }); + fireCustomEvent(self, "monster-popper-hide", { + self, + }); - self[popperElementSymbol].style.display = "none"; - removeAttributeToken(self[controlElementSymbol], "class", "open"); + self[popperElementSymbol].style.display = "none"; + removeAttributeToken(self[controlElementSymbol], "class", "open"); - setTimeout(() => { - fireCustomEvent(self, "monster-popper-hidden", { - self, - }); - }, 0); + setTimeout(() => { + fireCustomEvent(self, "monster-popper-hidden", { + self, + }); + }, 0); } /** * @private */ function show() { - const self = this; + const self = this; - if (self.getOption("disabled", false) === true) { - return; - } + if (self.getOption("disabled", false) === true) { + return; + } - if (self[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) { - return; - } + if (self[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) { + return; + } - fireCustomEvent(self, "monster-popper-open", { - self, - }); + fireCustomEvent(self, "monster-popper-open", { + self, + }); - self[popperElementSymbol].style.visibility = "hidden"; - self[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK; + self[popperElementSymbol].style.visibility = "hidden"; + self[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK; - addAttributeToken(self[controlElementSymbol], "class", "open"); - updatePopper.call(self); + addAttributeToken(self[controlElementSymbol], "class", "open"); + updatePopper.call(self); - setTimeout(() => { - fireCustomEvent(self, "monster-popper-opened", { - self, - }); - }, 0); + setTimeout(() => { + fireCustomEvent(self, "monster-popper-opened", { + self, + }); + }, 0); } /** * @private */ function updatePopper() { - if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) { - return; - } - - if (this.getOption("disabled", false) === true) { - return; - } - - positionPopper.call( - this, - this[controlElementSymbol], - this[popperElementSymbol], - this.getOption("popper", {}), - ); + if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) { + return; + } + + if (this.getOption("disabled", false) === true) { + return; + } + + positionPopper.call( + this, + this[controlElementSymbol], + this[popperElementSymbol], + this.getOption("popper", {}), + ); } /** @@ -331,105 +329,110 @@ function updatePopper() { * @fires monster-copy-error */ function initEventHandler() { - const self = this; - - this[closeEventHandler] = (event) => { - const path = event.composedPath(); - - for (const [, element] of Object.entries(path)) { - if (element === this) { - return; - } - } - hide.call(this); - }; - - const type = "click"; - - this[controlElementSymbol].addEventListener("mouseenter", (event) => { - if (this.getOption("features.preventOpenEventSent") === true) { - event.preventDefault(); - } - this.showDialog(); - }); - - this[controlElementSymbol].addEventListener("focus", (event) => { - if (this.getOption("features.preventOpenEventSent") === true) { - event.preventDefault(); - } - this.showDialog(); - }); - this[controlElementSymbol].addEventListener("blur", (event) => { - if (this.getOption("features.preventOpenEventSent") === true) { - event.preventDefault(); - } - this.hideDialog(); - }); - - this[copyButtonElementSymbol].addEventListener(type, function (event) { - - fireCustomEvent(self, "monster-copy-clicked", { - element: self, - }); - - const nodes = getSlottedElements.call(self, ":scope"); - - let text = ""; - for (const node of nodes) { - if (self.getOption("features.stripTags")) { - text += node.textContent; - } else { - text += node.outerHTML; - } - } - - navigator.clipboard.writeText(text).then(function () { - - self[copyButtonElementSymbol].querySelector("use").setAttribute("href", "#copy-success"); - setTimeout(() => { - self[copyButtonElementSymbol].querySelector("use").setAttribute("href", "#copy"); - }, 2000); - - fireCustomEvent(self, "monster-copy-success", { - element: self, - }); - - }).catch(function (e) { - - self[copyButtonElementSymbol].querySelector("use").setAttribute("href", "#copy-error"); - setTimeout(() => { - self[copyButtonElementSymbol].querySelector("use").setAttribute("href", "#copy"); - }, 2000); - - fireCustomEvent(self, "monster-copy-error", { - element: self, - }); - - addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, "" + e); - }) - }); - - return this; + const self = this; + + this[closeEventHandler] = (event) => { + const path = event.composedPath(); + + for (const [, element] of Object.entries(path)) { + if (element === this) { + return; + } + } + hide.call(this); + }; + + const type = "click"; + + this[controlElementSymbol].addEventListener("mouseenter", (event) => { + if (this.getOption("features.preventOpenEventSent") === true) { + event.preventDefault(); + } + this.showDialog(); + }); + + this[controlElementSymbol].addEventListener("focus", (event) => { + if (this.getOption("features.preventOpenEventSent") === true) { + event.preventDefault(); + } + this.showDialog(); + }); + this[controlElementSymbol].addEventListener("blur", (event) => { + if (this.getOption("features.preventOpenEventSent") === true) { + event.preventDefault(); + } + this.hideDialog(); + }); + + this[copyButtonElementSymbol].addEventListener(type, function (event) { + fireCustomEvent(self, "monster-copy-clicked", { + element: self, + }); + + const nodes = getSlottedElements.call(self, ":scope"); + + let text = ""; + for (const node of nodes) { + if (self.getOption("features.stripTags")) { + text += node.textContent; + } else { + text += node.outerHTML; + } + } + + navigator.clipboard + .writeText(text) + .then(function () { + self[copyButtonElementSymbol] + .querySelector("use") + .setAttribute("href", "#copy-success"); + setTimeout(() => { + self[copyButtonElementSymbol] + .querySelector("use") + .setAttribute("href", "#copy"); + }, 2000); + + fireCustomEvent(self, "monster-copy-success", { + element: self, + }); + }) + .catch(function (e) { + self[copyButtonElementSymbol] + .querySelector("use") + .setAttribute("href", "#copy-error"); + setTimeout(() => { + self[copyButtonElementSymbol] + .querySelector("use") + .setAttribute("href", "#copy"); + }, 2000); + + fireCustomEvent(self, "monster-copy-error", { + element: self, + }); + + addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, "" + e); + }); + }); + + return this; } - /** * @private * @return {void} */ function initControlReferences() { - this[controlElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}="control"]`, - ); - - this[copyButtonElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}="button"]`, - ); - - this[popperElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}="popper"]`, - ); + this[controlElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}="control"]`, + ); + + this[copyButtonElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}="button"]`, + ); + this[popperElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}="popper"]`, + ); } /** @@ -437,8 +440,8 @@ function initControlReferences() { * @return {string} */ function getTemplate() { - // language=HTML - return ` + // language=HTML + return ` <div data-monster-role="control" part="control"> <slot></slot> <div data-monster-role="popper" part="popper" tabindex="-1" class="monster-color-primary-1"> @@ -471,5 +474,4 @@ function getTemplate() { </div>`; } - registerCustomElement(Copy); diff --git a/source/components/content/stylesheet/copy.mjs b/source/components/content/stylesheet/copy.mjs index 07856fcda52ec3e4752d7f90d6bc1802dd8da432..287502ce311961d0ad6880178efdf7d95bb2aa8b 100644 --- a/source/components/content/stylesheet/copy.mjs +++ b/source/components/content/stylesheet/copy.mjs @@ -10,10 +10,10 @@ * For more information about purchasing a commercial license, please contact schukai GmbH. */ -import {addAttributeToken} from "../../../dom/attributes.mjs"; -import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs"; +import { addAttributeToken } from "../../../dom/attributes.mjs"; +import { ATTRIBUTE_ERRORMESSAGE } from "../../../dom/constants.mjs"; -export {CopyStyleSheet} +export { CopyStyleSheet }; /** * @private @@ -22,10 +22,17 @@ export {CopyStyleSheet} const CopyStyleSheet = new CSSStyleSheet(); try { - CopyStyleSheet.insertRule(` + CopyStyleSheet.insertRule( + ` @layer copy { [data-monster-role=control]{box-sizing:border-box;outline:none;width:100%}[data-monster-role=control].flex{align-items:center;display:flex;flex-direction:row}:host{box-sizing:border-box;display:block}:after,:before,:root{--monster-font-family:-apple-system,BlinkMacSystemFont,\"Quicksand\",\"Segoe UI\",\"Roboto\",\"Oxygen\",\"Ubuntu\",\"Cantarell\",\"Fira Sans\",\"Droid Sans\",\"Helvetica Neue\",Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\";--monster-color-primary-1:var(--monster-color-gray-6);--monster-color-primary-2:var(--monster-color-gray-6);--monster-color-primary-3:var(--monster-color-cinnamon-1);--monster-color-primary-4:var(--monster-color-cinnamon-1);--monster-bg-color-primary-1:var(--monster-color-gray-1);--monster-bg-color-primary-2:var(--monster-color-gray-2);--monster-bg-color-primary-3:var(--monster-color-gray-6);--monster-bg-color-primary-4:var(--monster-color-gray-4)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-color-primary-1:var(--monster-color-gray-1);--monster-color-primary-2:var(--monster-color-gray-1);--monster-color-primary-3:var(--monster-color-gray-6);--monster-color-primary-4:var(--monster-color-gray-6);--monster-bg-color-primary-1:var(--monster-color-gray-6);--monster-bg-color-primary-2:var(--monster-color-gray-3);--monster-bg-color-primary-3:var(--monster-color-gray-2);--monster-bg-color-primary-4:var(--monster-color-gray-1)}}:after,:before,:root{--monster-color-secondary-1:var(--monster-color-red-4);--monster-color-secondary-2:var(--monster-color-red-4);--monster-color-secondary-3:var(--monster-color-red-1);--monster-color-secondary-4:var(--monster-color-red-1);--monster-bg-color-secondary-1:var(--monster-color-gray-1);--monster-bg-color-secondary-2:var(--monster-color-red-2);--monster-bg-color-secondary-3:var(--monster-color-red-3);--monster-bg-color-secondary-4:var(--monster-color-red-6)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-color-secondary-1:var(--monster-color-red-1);--monster-color-secondary-2:var(--monster-color-red-1);--monster-color-secondary-3:var(--monster-color-red-6);--monster-color-secondary-4:var(--monster-color-red-4);--monster-bg-color-secondary-1:var(--monster-color-gray-6);--monster-bg-color-secondary-2:var(--monster-color-red-3);--monster-bg-color-secondary-3:var(--monster-color-red-2);--monster-bg-color-secondary-4:var(--monster-color-red-1)}}:after,:before,:root{--monster-color-tertiary-1:var(--monster-color-magenta-4);--monster-color-tertiary-2:var(--monster-color-magenta-4);--monster-color-tertiary-3:var(--monster-color-magenta-6);--monster-color-tertiary-4:var(--monster-color-magenta-1);--monster-bg-color-tertiary-1:var(--monster-color-gray-1);--monster-bg-color-tertiary-2:var(--monster-color-magenta-1);--monster-bg-color-tertiary-3:var(--monster-color-magenta-2);--monster-bg-color-tertiary-4:var(--monster-color-magenta-6)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-color-tertiary-1:var(--monster-color-magenta-1);--monster-color-tertiary-2:var(--monster-color-magenta-6);--monster-color-tertiary-3:var(--monster-color-magenta-4);--monster-color-tertiary-4:var(--monster-color-magenta-4);--monster-bg-color-tertiary-1:var(--monster-color-gray-6);--monster-bg-color-tertiary-2:var(--monster-color-magenta-2);--monster-bg-color-tertiary-3:var(--monster-color-magenta-1);--monster-bg-color-tertiary-4:var(--monster-color-magenta-1)}}:after,:before,:root{--monster-color-destructive-1:var(--monster-color-red-1);--monster-color-destructive-2:var(--monster-color-red-4);--monster-color-destructive-3:var(--monster-color-red-6);--monster-color-destructive-4:var(--monster-color-red-1);--monster-bg-color-destructive-1:var(--monster-color-red-4);--monster-bg-color-destructive-2:var(--monster-color-gray-1);--monster-bg-color-destructive-3:var(--monster-color-red-2);--monster-bg-color-destructive-4:var(--monster-color-red-5)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-color-destructive-1:var(--monster-color-red-1);--monster-color-destructive-2:var(--monster-color-red-3);--monster-color-destructive-3:var(--monster-color-red-4);--monster-color-destructive-4:var(--monster-color-red-1);--monster-bg-color-destructive-1:var(--monster-color-red-5);--monster-bg-color-destructive-2:var(--monster-color-gray-6);--monster-bg-color-destructive-3:var(--monster-color-red-1);--monster-bg-color-destructive-4:var(--monster-color-red-4)}}:after,:before,:root{--monster-color-success-1:var(--monster-color-green-1);--monster-color-success-2:var(--monster-color-green-4);--monster-color-success-3:var(--monster-color-green-6);--monster-color-success-4:var(--monster-color-green-1);--monster-bg-color-success-1:var(--monster-color-green-3);--monster-bg-color-success-2:var(--monster-color-gray-1);--monster-bg-color-success-3:var(--monster-color-green-2);--monster-bg-color-success-4:var(--monster-color-green-5)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-color-success-1:var(--monster-color-green-1);--monster-color-success-2:var(--monster-color-green-2);--monster-color-success-3:var(--monster-color-green-4);--monster-color-success-4:var(--monster-color-green-1);--monster-bg-color-success-1:var(--monster-color-green-5);--monster-bg-color-success-2:var(--monster-color-gray-6);--monster-bg-color-success-3:var(--monster-color-green-1);--monster-bg-color-success-4:var(--monster-color-green-3)}}:after,:before,:root{--monster-color-warning-1:var(--monster-color-orange-1);--monster-color-warning-2:var(--monster-color-orange-4);--monster-color-warning-3:var(--monster-color-orange-6);--monster-color-warning-4:var(--monster-color-orange-1);--monster-bg-color-warning-1:var(--monster-color-orange-3);--monster-bg-color-warning-2:var(--monster-color-gray-1);--monster-bg-color-warning-3:var(--monster-color-orange-2);--monster-bg-color-warning-4:var(--monster-color-orange-5)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-color-warning-1:var(--monster-color-orange-1);--monster-color-warning-2:var(--monster-color-orange-3);--monster-color-warning-3:var(--monster-color-orange-4);--monster-color-warning-4:var(--monster-color-orange-1);--monster-bg-color-warning-1:var(--monster-color-orange-5);--monster-bg-color-warning-2:var(--monster-color-gray-6);--monster-bg-color-warning-3:var(--monster-color-orange-1);--monster-bg-color-warning-4:var(--monster-color-orange-3)}}:after,:before,:root{--monster-color-error-1:var(--monster-color-red-1);--monster-color-error-2:var(--monster-color-red-4);--monster-color-error-3:var(--monster-color-red-6);--monster-color-error-4:var(--monster-color-red-1);--monster-bg-color-error-1:var(--monster-color-red-4);--monster-bg-color-error-2:var(--monster-color-gray-1);--monster-bg-color-error-3:var(--monster-color-red-2);--monster-bg-color-error-4:var(--monster-color-red-5)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-color-error-1:var(--monster-color-red-1);--monster-color-error-2:var(--monster-color-red-3);--monster-color-error-3:var(--monster-color-red-4);--monster-color-error-4:var(--monster-color-red-1);--monster-bg-color-error-1:var(--monster-color-red-5);--monster-bg-color-error-2:var(--monster-color-gray-6);--monster-bg-color-error-3:var(--monster-color-red-1);--monster-bg-color-error-4:var(--monster-color-red-4)}}:after,:before,:root{--monster-color-selection-1:var(--monster-color-gray-6);--monster-color-selection-2:var(--monster-color-gray-6);--monster-color-selection-3:var(--monster-color-gray-6);--monster-color-selection-4:var(--monster-color-gray-1);--monster-bg-color-selection-1:var(--monster-color-yellow-2);--monster-bg-color-selection-2:var(--monster-color-yellow-1);--monster-bg-color-selection-3:var(--monster-color-yellow-2);--monster-bg-color-selection-4:var(--monster-color-yellow-6)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-color-selection-1:var(--monster-color-gray-6);--monster-color-selection-2:var(--monster-color-gray-6);--monster-color-selection-3:var(--monster-color-gray-6);--monster-color-selection-4:var(--monster-color-gray-1);--monster-bg-color-selection-1:var(--monster-color-yellow-2);--monster-bg-color-selection-2:var(--monster-color-yellow-1);--monster-bg-color-selection-3:var(--monster-color-yellow-2);--monster-bg-color-selection-4:var(--monster-color-yellow-6)}}:after,:before,:root{--monster-color-primary-disabled-1:var(--monster-color-gray-4);--monster-color-primary-disabled-2:var(--monster-color-gray-4);--monster-color-primary-disabled-3:var(--monster-color-gray-4);--monster-color-primary-disabled-4:var(--monster-color-gray-4);--monster-bg-color-primary-disabled-1:var(--monster-color-gray-1);--monster-bg-color-primary-disabled-2:var(--monster-color-gray-2);--monster-bg-color-primary-disabled-3:var(--monster-color-gray-3);--monster-bg-color-primary-disabled-4:var(--monster-color-gray-6)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-color-primary-disabled-1:var(--monster-color-gray-4);--monster-color-primary-disabled-2:var(--monster-color-gray-4);--monster-color-primary-disabled-3:var(--monster-color-gray-3);--monster-color-primary-disabled-4:var(--monster-color-gray-3);--monster-bg-color-primary-disabled-1:var(--monster-color-gray-6);--monster-bg-color-primary-disabled-2:var(--monster-color-gray-3);--monster-bg-color-primary-disabled-3:var(--monster-color-gray-2);--monster-bg-color-primary-disabled-4:var(--monster-color-gray-1)}}:after,:before,:root{--monster-color-gradient-1:#833ab4;--monster-color-gradient-2:#fd1d1d;--monster-color-gradient-3:#fcb045;--monster-box-shadow-1:none;--monster-box-shadow-2:-1px 1px 10px 1px hsla(0,0%,76%,.61);--monster-text-shadow:none;--monster-theme-control-bg-color:var(--monster-color-seashell-1);--monster-theme-control-color:var(--monster-color-seashell-6);--monster-theme-control-hover-color:var(--monster-color-seashell-6);--monster-theme-control-hover-bg-color:var(--monster-color-seashell-2);--monster-theme-control-border-width:2px;--monster-theme-control-border-style:solid;--monster-theme-control-border-radius:0;--monster-theme-control-border-color:var(--monster-color-primary-1)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-theme-control-bg-color:var(--monster-color-gray-5);--monster-theme-control-color:var(--monster-color-gray-1);--monster-theme-control-border-color:var(--monster-color-gray-3);--monster-theme-control-hover-color:var(--monster-color-gray-1);--monster-theme-control-hover-bg-color:var(--monster-color-gray-6)}}:after,:before,:root{--monster-theme-on-color:var(--monster-color-green-1);--monster-theme-on-bg-color:var(--monster-color-green-5);--monster-theme-off-color:var(--monster-color-gray-1);--monster-theme-off-bg-color:var(--monster-color-gray-4)}@media (prefers-color-scheme:dark){:after,:before,:root{--monster-theme-on-color:var(--monster-color-gray-6);--monster-theme-on-bg-color:var(--monster-color-gray-1);--monster-theme-off-color:var(--monster-color-gray-1);--monster-theme-off-bg-color:var(--monster-color-gray-5)}}:after,:before,:root{--monster-border-style:solid;--monster-border-width:3px;--monster-border-radius:0;--monster-popper-witharrrow-distance:-4px;--monster-z-index-default:0;--monster-z-index-outline:10;--monster-z-index-dropdown:200;--monster-z-index-dropdown-overlay:210;--monster-z-index-sticky:300;--monster-z-index-sticky-overlay:310;--monster-z-index-fixed:400;--monster-z-index-fixed-overlay:410;--monster-z-index-modal-backdrop:500;--monster-z-index-modal-backdrop-overlay:510;--monster-z-index-offcanvas:600;--monster-z-index-offcanvas-overlay:610;--monster-z-index-modal:700;--monster-z-index-modal-overlay:710;--monster-z-index-popover:800;--monster-z-index-popover-overlay:810;--monster-z-index-tooltip:800;--monster-z-index-tooltip-overlay:910;--monster-space-0:0;--monster-space-1:2px;--monster-space-2:4px;--monster-space-3:6px;--monster-space-4:10px;--monster-space-5:16px;--monster-space-6:26px;--monster-space-7:42px;--monster-breakpoint-0:480px;--monster-breakpoint-4:480px;--monster-breakpoint-7:768px;--monster-breakpoint-9:992px;--monster-breakpoint-12:1200px;--monster-dragger-width:2px;--monster-dragger-handle-width:4px;--monster-dragger-handle-height:50px}div[data-monster-role=popper]{align-content:center;background:var(--monster-bg-color-primary-1);border-color:var(--monster-bg-color-primary-4);border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);box-shadow:var(--monster-box-shadow-1);box-sizing:border-box;color:var(--monster-color-primary-1);display:none;justify-content:space-between;left:0;padding:1.1em;position:absolute;top:0;width:-moz-max-content;width:max-content;z-index:var(--monster-z-index-modal)}div[data-monster-role=popper] div[data-monster-role=arrow]{background:var(--monster-bg-color-primary-1);height:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);pointer-events:none;position:absolute;width:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);z-index:-1}:host{display:inline-block}[data-monster-role=control]{display:inherit}[data-monster-role=icon]{fill:var(--monster-color-primary-1)}[data-monster-role=icon-map]{display:none}button{background:inherit;border:none}button:hover{cursor:copy}button:active{transform:scale(.95)} -}`, 0); +}`, + 0, + ); } catch (e) { - addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + ""); + addAttributeToken( + document.getRootNode().querySelector("html"), + ATTRIBUTE_ERRORMESSAGE, + e + "", + ); } diff --git a/source/components/form/field-set.mjs b/source/components/form/field-set.mjs index 187131f5f14c3da2644ecebaafc67950df49eaf5..67066e61e578be465989164aceb292a4e8c887b7 100644 --- a/source/components/form/field-set.mjs +++ b/source/components/form/field-set.mjs @@ -268,9 +268,8 @@ function updateColumns() { this[fieldSetElementSymbol].classList.remove("multiple-columns"); return; } - + this[fieldSetElementSymbol].classList.add("multiple-columns"); - } /** diff --git a/source/components/form/select.mjs b/source/components/form/select.mjs index b885c98c1f8809bec2e491d38d69275b4de1ffee..dbed3026eafb97da03ad6429004a6e2b5e9d8bcf 100644 --- a/source/components/form/select.mjs +++ b/source/components/form/select.mjs @@ -12,61 +12,61 @@ * SPDX-License-Identifier: AGPL-3.0 */ -import {instanceSymbol} from "../../constants.mjs"; -import {internalSymbol} from "../../constants.mjs"; -import {buildMap} from "../../data/buildmap.mjs"; -import {DeadMansSwitch} from "../../util/deadmansswitch.mjs"; -import {positionPopper} from "./util/floating-ui.mjs"; +import { instanceSymbol } from "../../constants.mjs"; +import { internalSymbol } from "../../constants.mjs"; +import { buildMap } from "../../data/buildmap.mjs"; +import { DeadMansSwitch } from "../../util/deadmansswitch.mjs"; +import { positionPopper } from "./util/floating-ui.mjs"; import { - addAttributeToken, - findClosestByAttribute, - removeAttributeToken, + addAttributeToken, + findClosestByAttribute, + removeAttributeToken, } from "../../dom/attributes.mjs"; import { - ATTRIBUTE_ERRORMESSAGE, - ATTRIBUTE_PREFIX, - ATTRIBUTE_ROLE, + ATTRIBUTE_ERRORMESSAGE, + ATTRIBUTE_PREFIX, + ATTRIBUTE_ROLE, } from "../../dom/constants.mjs"; -import {CustomControl} from "../../dom/customcontrol.mjs"; +import { CustomControl } from "../../dom/customcontrol.mjs"; import { - assembleMethodSymbol, - getSlottedElements, - registerCustomElement, + assembleMethodSymbol, + getSlottedElements, + registerCustomElement, } from "../../dom/customelement.mjs"; import { - findTargetElementFromEvent, - fireCustomEvent, - fireEvent, + findTargetElementFromEvent, + fireCustomEvent, + fireEvent, } from "../../dom/events.mjs"; -import {getDocument} from "../../dom/util.mjs"; -import {Formatter} from "../../text/formatter.mjs"; -import {getGlobal} from "../../types/global.mjs"; -import {ID} from "../../types/id.mjs"; +import { getDocument } from "../../dom/util.mjs"; +import { Formatter } from "../../text/formatter.mjs"; +import { getGlobal } from "../../types/global.mjs"; +import { ID } from "../../types/id.mjs"; import { - isArray, - isFunction, - isInteger, - isIterable, - isObject, - isPrimitive, - isString, + isArray, + isFunction, + isInteger, + isIterable, + isObject, + isPrimitive, + isString, } from "../../types/is.mjs"; -import {Observer} from "../../types/observer.mjs"; -import {ProxyObserver} from "../../types/proxyobserver.mjs"; -import {validateArray, validateString} from "../../types/validate.mjs"; -import {Processing} from "../../util/processing.mjs"; -import {STYLE_DISPLAY_MODE_BLOCK} from "./constants.mjs"; -import {SelectStyleSheet} from "./stylesheet/select.mjs"; +import { Observer } from "../../types/observer.mjs"; +import { ProxyObserver } from "../../types/proxyobserver.mjs"; +import { validateArray, validateString } from "../../types/validate.mjs"; +import { Processing } from "../../util/processing.mjs"; +import { STYLE_DISPLAY_MODE_BLOCK } from "./constants.mjs"; +import { SelectStyleSheet } from "./stylesheet/select.mjs"; import { - getDocumentTranslations, - Translations, + getDocumentTranslations, + Translations, } from "../../i18n/translations.mjs"; export { - Select, - popperElementSymbol, - getSummaryTemplate, - getSelectionTemplate, + Select, + popperElementSymbol, + getSummaryTemplate, + getSelectionTemplate, }; /** @@ -199,7 +199,7 @@ const popperFilterElementSymbol = Symbol("popperFilterElement"); * @type {Symbol} */ const popperFilterContainerElementSymbol = Symbol( - "popperFilterContainerElement", + "popperFilterContainerElement", ); /** @@ -285,585 +285,581 @@ const FILTER_POSITION_INLINE = "inline"; * @fires monster-changed */ class Select extends CustomControl { - - /** - * - */ - constructor() { - super(); - initOptionObserver.call(this); - } - - /** - * This method is called by the `instanceof` operator. - * @returns {Symbol} - */ - static get [instanceSymbol]() { - return Symbol.for("@schukai/monster/components/form/select@@instance"); - } - - /** - * The current selection of the Select - * - * ``` - * e = document.querySelector('monster-select'); - * console.log(e.value) - * // ↦ 1 - * // ↦ ['1','2'] - * ``` - * - * @returns {string} - */ - get value() { - return convertSelectionToValue.call(this, this.getOption("selection")); - } - - /** - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals} - * @return {boolean} - */ - static get formAssociated() { - return true; - } - - /** - * Set selection - * - * ``` - * e = document.querySelector('monster-select'); - * e.value=1 - * ``` - * - * @property {string|array} value - * @throws {Error} unsupported type - */ - set value(value) { - const result = convertValueToSelection.call(this, value); - setSelection - .call(this, result.selection) - .then(() => { - }) - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - }); - } - - /** - * To set the options via the HTML tag, the attribute `data-monster-options` must be used. - * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} - * - * The individual configuration values can be found in the table. - * - * @property {Object} toggleEventType=click,touch List of event types to be observed for opening the dropdown - * @property {boolean} delegatesFocus=false lorem [see mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/delegatesFocus) - * @property {Object[]} options Selection of key identifier pairs available for selection and displayed in the dropdown. - * @property {string} options[].label - * @property {string} options[].value - * @property {string} options[].visibility hidden or visible - * @property {Array} selection Selected options - * @property {Integer} showMaxOptions=10 Maximum number of visible options before a scroll bar should be displayed. - * @property {string} type=radio Multiple (checkbox) or single selection (radio) - * @property {string} name=(random id) Name of the form field - * @property {string} url Load options from server per url - * @property {string} lookup Load options from server per url - * @property {boolean} lookup.url=null Load options from server per url - * @property {boolean} lookup.individually=false Load options individually - * @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) - * @property {String} fetch.redirect=error - * @property {String} fetch.method=GET - * @property {String} fetch.mode=same-origin - * @property {String} fetch.credentials=same-origin - * @property {Object} fetch.headers={"accept":"application/json"}} - * @property {Object} labels - * @property {string} labels.cannot-be-loaded cannot be loaded - * @property {string} labels.no-options-available no options available - * @property {string} labels.select-an-option select an option - * @property {string} labels.no-option no option in the list, maybe you have to change the filter - * @property {Object} features List with features - * @property {Boolean} features.clearAll=true Display of a delete button to delete the entire selection - * @property {Boolean} features.clear=true Display of a delete key for deleting the specific selection - * @property {Boolean} features.lazyLoad=false Load options when first opening the dropdown - * @property {Boolean} features.closeOnSelect=false Close the dropdown when an option is selected (since 3.54.0) - * @property {Boolean} features.emptyValueIfNoOptions=false If no options are available, the selection is set to an empty array - * @property {Boolean} features.storeFetchedData=false Store fetched data in the object - * @property {Boolean} features.useStrictValueComparison=true Use strict value comparison for the selection - * @property {Boolean} filter.defaultValue=* Default filter value, if the filter is empty - * @property {Boolean} filter.mode=options Filter mode, values: options, remote, disabled - * @property {Object} templates Template definitions - * @property {string} templates.main Main template - * @property {string} templateMapping Mapping of the template placeholders - * @property {string} templateMapping.selected Selected Template - * @property {Object} popper [PopperJS Options](https://popper.js.org/docs/v2/) - * @property {string} popper.placement=bottom PopperJS placement - * @property {Object[]} modifiers={name:offset} PopperJS placement - * @property {Object} mapping - * @property {String} mapping.selector=* Path to select the appropriate entries - * @property {String} mapping.labelTemplate="" template with the label placeholders in the form ${name}, where name is the key (**) - * @property {String} mapping.valueTemplate="" template with the value placeholders in the form ${name}, where name is the key - * @property {Monster.Components.Form~exampleFilterCallback|undefined} mapping.filter Filtering of values via a function - * @property {Object} formatter - * @property {Monster.Components.Form~formatterSelectionCallback|undefined} formatter.selection format selection label - */ - get defaults() { - return Object.assign( - {}, - super.defaults, - { - toggleEventType: ["click", "touch"], - delegatesFocus: false, - options: [], - selection: [], - showMaxOptions: 10, - type: "radio", - name: new ID("s").toString(), - features: { - clearAll: true, - clear: true, - lazyLoad: false, - closeOnSelect: false, - emptyValueIfNoOptions: false, - storeFetchedData: false, - useStrictValueComparison: false, - }, - url: null, - lookup: { - url: null, - grouping: false, - }, - labels: { - "cannot-be-loaded": "Cannot be loaded", - "no-options-available": noOptionsAvailableMessage, - "click-to-load-options": clickToLoadOptionsMessage, - "select-an-option": "Select an option", - "summary-text": { - zero: "No entries were selected", - one: '<span class="monster-badge-primary-pill">1</span> entry was selected', - other: - '<span class="monster-badge-primary-pill">${count}</span> entries were selected', - }, - "no-options": - "Unfortunately, there are no options available in the list.", - "no-options-found": - "No options are available in the list. Please consider modifying the filter.", - }, - messages: { - control: null, - selected: null, - emptyOptions: null, - }, - fetch: { - redirect: "error", - method: "GET", - mode: "same-origin", - credentials: "same-origin", - headers: { - accept: "application/json", - }, - }, - filter: { - defaultValue: "*", - mode: FILTER_MODE_DISABLED, - position: FILTER_POSITION_INLINE, - marker: { - open: "{", - close: "}", - }, - }, - classes: { - badge: "monster-badge-primary", - statusOrRemoveBadge: "empty", - }, - mapping: { - selector: "*", - labelTemplate: "", - valueTemplate: "", - filter: null, - }, - formatter: { - selection: buildSelectionLabel, - }, - templates: { - main: getTemplate(), - }, - templateMapping: { - /** with the attribute `data-monster-selected-template` the template for the selected options can be defined. */ - selected: getSelectionTemplate(), - }, - - popper: { - placement: "bottom", - middleware: ["flip", "offset:1"], - }, - }, - initOptionsFromArguments.call(this), - ); - } - - /** - * @return {Select} - */ - [assembleMethodSymbol]() { - const self = this; - super[assembleMethodSymbol](); - - initControlReferences.call(self); - initEventHandler.call(self); - - const lazyLoadFlag = self.getOption("features.lazyLoad"); - - if (self.hasAttribute("value")) { - new Processing(10, () => { - this.value = this.getAttribute("value"); - }) - .run() - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - }); - } - - if (self.getOption("url") !== null) { - - if (lazyLoadFlag) { - lookupSelection.call(self); - } else { - self.fetch().catch((e) => { - addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`); - }); - } - } - - let lastValue = self.value; - self[internalSymbol].attachObserver( - new Observer(function () { - if (isObject(this) && this instanceof ProxyObserver) { - const n = this.getSubject()?.options?.value; - - if (lastValue !== n) { - lastValue = n; - setSelection - .call(self, n) - .then(() => { - }) - .catch((e) => { - addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`); - }); - } - } - }), - ); - - areOptionsAvailableAndInit.call(self); - - return this; - } - - /** - * - * @returns {*} - * @throws {Error} storeFetchedData is not enabled - * @since 3.66.0 - */ - getLastFetchedData() { - if (this.getOption("features.storeFetchedData") === false) { - throw new Error("storeFetchedData is not enabled"); - } - - return this?.[lastFetchedDataSymbol]; - } - - /** - * The Button.click() method simulates a click on the internal button element. - * - * @since 3.27.0 - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click} - */ - click() { - if (this.getOption("disabled") === true) { - return; - } - - toggle.call(this); - } - - /** - * The Button.focus() method sets focus on the internal button element. - * - * @since 3.27.0 - * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus} - */ - focus(options) { - if (this.getOption("disabled") === true) { - return; - } - - new Processing(() => { - gatherState.call(this); - focusFilter.call(this, options); - }) - .run() - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); - }); - } - - /** - * The Button.blur() method removes focus from the internal button element. - * @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/blur - */ - blur() { - new Processing(() => { - gatherState.call(this); - blurFilter.call(this); - }) - .run() - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); - }); - } - - /** - * If no url is specified, the options are taken from the Component itself. - * - * @param {string|URL} url URL to fetch the options - * @return {Promise} - */ - fetch(url) { - if (url instanceof URL) { - url = url.toString(); - } - - if (url !== undefined && url !== null) { - url = validateString(url); - } else { - url = this.getOption("url"); - if (url === null) { - return Promise.reject(new Error("No url defined")); - } - } - - hide.call(this); - - return new Promise((resolve, reject) => { - setStatusOrRemoveBadges.call(this, "loading"); - - new Processing(10, () => { - this.setOption("options", []); - - fetchData - .call(this, url) - .then((map) => { - if ( - isObject(map) || - isArray(map) || - map instanceof Set || - map instanceof Map - ) { - - try { - this.importOptions(map); - } catch (e) { - setStatusOrRemoveBadges.call(this, "error"); - reject(e); - return; - } - - this[lastFetchedDataSymbol] = map; - - let result; - const selection = this.getOption("selection"); - let newValue = []; - if (selection) { - newValue = selection; - } else if (this.hasAttribute("value")) { - newValue = this.getAttribute("value"); - } - - result = setSelection.call(this, newValue); - requestAnimationFrame(() => { - checkOptionState.call(this); - setStatusOrRemoveBadges.call(this, "closed"); - resolve(result); - }); - - return; - } - - setStatusOrRemoveBadges.call(this, "error"); - reject(new Error("invalid response")); - }) - .catch((e) => { - setStatusOrRemoveBadges.call(this, "error"); - reject(e); - }); - }) - .run() - .catch((e) => { - setStatusOrRemoveBadges.call(this, "error"); - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - reject(e); - }); - }); - } - - /** - * @return {void} - */ - connectedCallback() { - super.connectedCallback(); - const document = getDocument(); - - for (const [, type] of Object.entries(["click", "touch"])) { - // close on outside ui-events - document.addEventListener(type, this[closeEventHandler]); - } - - parseSlotsToOptions.call(this); - attachResizeObserver.call(this); - updatePopper.call(this); - - new Processing(() => { - gatherState.call(this); - focusFilter.call(this); - }).run(); - } - - /** - * @return {void} - */ - disconnectedCallback() { - super.disconnectedCallback(); - const document = getDocument(); - - // close on outside ui-events - for (const [, type] of Object.entries(["click", "touch"])) { - document.removeEventListener(type, this[closeEventHandler]); - } - - disconnectResizeObserver.call(this); - } - - /** - * Import Select Options from dataset - * Not to be confused with the control defaults/options - * - * @param {array|object|Map|Set} data - * @return {Select} - * @throws {Error} map is not iterable - * @throws {Error} missing label configuration - */ - importOptions(data) { - const mappingOptions = this.getOption("mapping", {}); - const selector = mappingOptions?.["selector"]; - const labelTemplate = mappingOptions?.["labelTemplate"]; - const valueTemplate = mappingOptions?.["valueTemplate"]; - const filter = mappingOptions?.["filter"]; - - let flag = false; - if (labelTemplate === "") { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty label template"); - flag = true; - } - - if (valueTemplate === "") { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty value template"); - flag = true; - } - - if (flag === true) { - throw new Error("missing label configuration"); - } - - const map = buildMap(data, selector, labelTemplate, valueTemplate, filter); - - const options = []; - if (!isIterable(map)) { - throw new Error("map is not iterable"); - } - - const visibility = "visible"; - - map.forEach((label, value) => { - options.push({ - value, - label, - visibility, - data: map.get(value), - }); - }); - - runAsOptionLengthChanged.call(this, map.size); - this.setOption("options", options); - - fireCustomEvent(this, "monster-options-set", { - options, - }); - - return this; - } - - /** - * @private - * @return {Select} - */ - calcAndSetOptionsDimension() { - calcAndSetOptionsDimension.call(this); - return this; - } - - /** - * - * @return {string} - */ - static getTag() { - return "monster-select"; - } - - /** - * - * @return {CSSStyleSheet[]} - */ - static getCSSStyleSheet() { - return [SelectStyleSheet]; - } + /** + * + */ + constructor() { + super(); + initOptionObserver.call(this); + } + + /** + * This method is called by the `instanceof` operator. + * @returns {Symbol} + */ + static get [instanceSymbol]() { + return Symbol.for("@schukai/monster/components/form/select@@instance"); + } + + /** + * The current selection of the Select + * + * ``` + * e = document.querySelector('monster-select'); + * console.log(e.value) + * // ↦ 1 + * // ↦ ['1','2'] + * ``` + * + * @returns {string} + */ + get value() { + return convertSelectionToValue.call(this, this.getOption("selection")); + } + + /** + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/attachInternals} + * @return {boolean} + */ + static get formAssociated() { + return true; + } + + /** + * Set selection + * + * ``` + * e = document.querySelector('monster-select'); + * e.value=1 + * ``` + * + * @property {string|array} value + * @throws {Error} unsupported type + */ + set value(value) { + const result = convertValueToSelection.call(this, value); + setSelection + .call(this, result.selection) + .then(() => {}) + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + }); + } + + /** + * To set the options via the HTML tag, the attribute `data-monster-options` must be used. + * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} + * + * The individual configuration values can be found in the table. + * + * @property {Object} toggleEventType=click,touch List of event types to be observed for opening the dropdown + * @property {boolean} delegatesFocus=false lorem [see mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/delegatesFocus) + * @property {Object[]} options Selection of key identifier pairs available for selection and displayed in the dropdown. + * @property {string} options[].label + * @property {string} options[].value + * @property {string} options[].visibility hidden or visible + * @property {Array} selection Selected options + * @property {Integer} showMaxOptions=10 Maximum number of visible options before a scroll bar should be displayed. + * @property {string} type=radio Multiple (checkbox) or single selection (radio) + * @property {string} name=(random id) Name of the form field + * @property {string} url Load options from server per url + * @property {string} lookup Load options from server per url + * @property {boolean} lookup.url=null Load options from server per url + * @property {boolean} lookup.individually=false Load options individually + * @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) + * @property {String} fetch.redirect=error + * @property {String} fetch.method=GET + * @property {String} fetch.mode=same-origin + * @property {String} fetch.credentials=same-origin + * @property {Object} fetch.headers={"accept":"application/json"}} + * @property {Object} labels + * @property {string} labels.cannot-be-loaded cannot be loaded + * @property {string} labels.no-options-available no options available + * @property {string} labels.select-an-option select an option + * @property {string} labels.no-option no option in the list, maybe you have to change the filter + * @property {Object} features List with features + * @property {Boolean} features.clearAll=true Display of a delete button to delete the entire selection + * @property {Boolean} features.clear=true Display of a delete key for deleting the specific selection + * @property {Boolean} features.lazyLoad=false Load options when first opening the dropdown + * @property {Boolean} features.closeOnSelect=false Close the dropdown when an option is selected (since 3.54.0) + * @property {Boolean} features.emptyValueIfNoOptions=false If no options are available, the selection is set to an empty array + * @property {Boolean} features.storeFetchedData=false Store fetched data in the object + * @property {Boolean} features.useStrictValueComparison=true Use strict value comparison for the selection + * @property {Boolean} filter.defaultValue=* Default filter value, if the filter is empty + * @property {Boolean} filter.mode=options Filter mode, values: options, remote, disabled + * @property {Object} templates Template definitions + * @property {string} templates.main Main template + * @property {string} templateMapping Mapping of the template placeholders + * @property {string} templateMapping.selected Selected Template + * @property {Object} popper [PopperJS Options](https://popper.js.org/docs/v2/) + * @property {string} popper.placement=bottom PopperJS placement + * @property {Object[]} modifiers={name:offset} PopperJS placement + * @property {Object} mapping + * @property {String} mapping.selector=* Path to select the appropriate entries + * @property {String} mapping.labelTemplate="" template with the label placeholders in the form ${name}, where name is the key (**) + * @property {String} mapping.valueTemplate="" template with the value placeholders in the form ${name}, where name is the key + * @property {Monster.Components.Form~exampleFilterCallback|undefined} mapping.filter Filtering of values via a function + * @property {Object} formatter + * @property {Monster.Components.Form~formatterSelectionCallback|undefined} formatter.selection format selection label + */ + get defaults() { + return Object.assign( + {}, + super.defaults, + { + toggleEventType: ["click", "touch"], + delegatesFocus: false, + options: [], + selection: [], + showMaxOptions: 10, + type: "radio", + name: new ID("s").toString(), + features: { + clearAll: true, + clear: true, + lazyLoad: false, + closeOnSelect: false, + emptyValueIfNoOptions: false, + storeFetchedData: false, + useStrictValueComparison: false, + }, + url: null, + lookup: { + url: null, + grouping: false, + }, + labels: { + "cannot-be-loaded": "Cannot be loaded", + "no-options-available": noOptionsAvailableMessage, + "click-to-load-options": clickToLoadOptionsMessage, + "select-an-option": "Select an option", + "summary-text": { + zero: "No entries were selected", + one: '<span class="monster-badge-primary-pill">1</span> entry was selected', + other: + '<span class="monster-badge-primary-pill">${count}</span> entries were selected', + }, + "no-options": + "Unfortunately, there are no options available in the list.", + "no-options-found": + "No options are available in the list. Please consider modifying the filter.", + }, + messages: { + control: null, + selected: null, + emptyOptions: null, + }, + fetch: { + redirect: "error", + method: "GET", + mode: "same-origin", + credentials: "same-origin", + headers: { + accept: "application/json", + }, + }, + filter: { + defaultValue: "*", + mode: FILTER_MODE_DISABLED, + position: FILTER_POSITION_INLINE, + marker: { + open: "{", + close: "}", + }, + }, + classes: { + badge: "monster-badge-primary", + statusOrRemoveBadge: "empty", + }, + mapping: { + selector: "*", + labelTemplate: "", + valueTemplate: "", + filter: null, + }, + formatter: { + selection: buildSelectionLabel, + }, + templates: { + main: getTemplate(), + }, + templateMapping: { + /** with the attribute `data-monster-selected-template` the template for the selected options can be defined. */ + selected: getSelectionTemplate(), + }, + + popper: { + placement: "bottom", + middleware: ["flip", "offset:1"], + }, + }, + initOptionsFromArguments.call(this), + ); + } + + /** + * @return {Select} + */ + [assembleMethodSymbol]() { + const self = this; + super[assembleMethodSymbol](); + + initControlReferences.call(self); + initEventHandler.call(self); + + const lazyLoadFlag = self.getOption("features.lazyLoad"); + + if (self.hasAttribute("value")) { + new Processing(10, () => { + this.value = this.getAttribute("value"); + }) + .run() + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + }); + } + + if (self.getOption("url") !== null) { + if (lazyLoadFlag) { + lookupSelection.call(self); + } else { + self.fetch().catch((e) => { + addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`); + }); + } + } + + let lastValue = self.value; + self[internalSymbol].attachObserver( + new Observer(function () { + if (isObject(this) && this instanceof ProxyObserver) { + const n = this.getSubject()?.options?.value; + + if (lastValue !== n) { + lastValue = n; + setSelection + .call(self, n) + .then(() => {}) + .catch((e) => { + addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`); + }); + } + } + }), + ); + + areOptionsAvailableAndInit.call(self); + + return this; + } + + /** + * + * @returns {*} + * @throws {Error} storeFetchedData is not enabled + * @since 3.66.0 + */ + getLastFetchedData() { + if (this.getOption("features.storeFetchedData") === false) { + throw new Error("storeFetchedData is not enabled"); + } + + return this?.[lastFetchedDataSymbol]; + } + + /** + * The Button.click() method simulates a click on the internal button element. + * + * @since 3.27.0 + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click} + */ + click() { + if (this.getOption("disabled") === true) { + return; + } + + toggle.call(this); + } + + /** + * The Button.focus() method sets focus on the internal button element. + * + * @since 3.27.0 + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus} + */ + focus(options) { + if (this.getOption("disabled") === true) { + return; + } + + new Processing(() => { + gatherState.call(this); + focusFilter.call(this, options); + }) + .run() + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); + }); + } + + /** + * The Button.blur() method removes focus from the internal button element. + * @link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/blur + */ + blur() { + new Processing(() => { + gatherState.call(this); + blurFilter.call(this); + }) + .run() + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); + }); + } + + /** + * If no url is specified, the options are taken from the Component itself. + * + * @param {string|URL} url URL to fetch the options + * @return {Promise} + */ + fetch(url) { + if (url instanceof URL) { + url = url.toString(); + } + + if (url !== undefined && url !== null) { + url = validateString(url); + } else { + url = this.getOption("url"); + if (url === null) { + return Promise.reject(new Error("No url defined")); + } + } + + hide.call(this); + + return new Promise((resolve, reject) => { + setStatusOrRemoveBadges.call(this, "loading"); + + new Processing(10, () => { + this.setOption("options", []); + + fetchData + .call(this, url) + .then((map) => { + if ( + isObject(map) || + isArray(map) || + map instanceof Set || + map instanceof Map + ) { + try { + this.importOptions(map); + } catch (e) { + setStatusOrRemoveBadges.call(this, "error"); + reject(e); + return; + } + + this[lastFetchedDataSymbol] = map; + + let result; + const selection = this.getOption("selection"); + let newValue = []; + if (selection) { + newValue = selection; + } else if (this.hasAttribute("value")) { + newValue = this.getAttribute("value"); + } + + result = setSelection.call(this, newValue); + requestAnimationFrame(() => { + checkOptionState.call(this); + setStatusOrRemoveBadges.call(this, "closed"); + resolve(result); + }); + + return; + } + + setStatusOrRemoveBadges.call(this, "error"); + reject(new Error("invalid response")); + }) + .catch((e) => { + setStatusOrRemoveBadges.call(this, "error"); + reject(e); + }); + }) + .run() + .catch((e) => { + setStatusOrRemoveBadges.call(this, "error"); + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + reject(e); + }); + }); + } + + /** + * @return {void} + */ + connectedCallback() { + super.connectedCallback(); + const document = getDocument(); + + for (const [, type] of Object.entries(["click", "touch"])) { + // close on outside ui-events + document.addEventListener(type, this[closeEventHandler]); + } + + parseSlotsToOptions.call(this); + attachResizeObserver.call(this); + updatePopper.call(this); + + new Processing(() => { + gatherState.call(this); + focusFilter.call(this); + }).run(); + } + + /** + * @return {void} + */ + disconnectedCallback() { + super.disconnectedCallback(); + const document = getDocument(); + + // close on outside ui-events + for (const [, type] of Object.entries(["click", "touch"])) { + document.removeEventListener(type, this[closeEventHandler]); + } + + disconnectResizeObserver.call(this); + } + + /** + * Import Select Options from dataset + * Not to be confused with the control defaults/options + * + * @param {array|object|Map|Set} data + * @return {Select} + * @throws {Error} map is not iterable + * @throws {Error} missing label configuration + */ + importOptions(data) { + const mappingOptions = this.getOption("mapping", {}); + const selector = mappingOptions?.["selector"]; + const labelTemplate = mappingOptions?.["labelTemplate"]; + const valueTemplate = mappingOptions?.["valueTemplate"]; + const filter = mappingOptions?.["filter"]; + + let flag = false; + if (labelTemplate === "") { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty label template"); + flag = true; + } + + if (valueTemplate === "") { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "empty value template"); + flag = true; + } + + if (flag === true) { + throw new Error("missing label configuration"); + } + + const map = buildMap(data, selector, labelTemplate, valueTemplate, filter); + + const options = []; + if (!isIterable(map)) { + throw new Error("map is not iterable"); + } + + const visibility = "visible"; + + map.forEach((label, value) => { + options.push({ + value, + label, + visibility, + data: map.get(value), + }); + }); + + runAsOptionLengthChanged.call(this, map.size); + this.setOption("options", options); + + fireCustomEvent(this, "monster-options-set", { + options, + }); + + return this; + } + + /** + * @private + * @return {Select} + */ + calcAndSetOptionsDimension() { + calcAndSetOptionsDimension.call(this); + return this; + } + + /** + * + * @return {string} + */ + static getTag() { + return "monster-select"; + } + + /** + * + * @return {CSSStyleSheet[]} + */ + static getCSSStyleSheet() { + return [SelectStyleSheet]; + } } function lookupSelection() { - const self = this; - - setTimeout(() => { - - const selection = self.getOption("selection"); - if (selection.length === 0) { - return; - } - - if (self[isLoadingSymbol] === true) { - return; - } - - if (self[lazyLoadDoneSymbol] === true) { - return; - } - - let url = self.getOption("url"); - let lookupUrl = self.getOption("lookup.url"); - if (lookupUrl !== null) { - url = lookupUrl; - } - - if(this.getOption("lookup.grouping") === true) { - filterFromRemoteByValue.call(self, url, selection.map((s) => s?.["value"])); - return; - } - - for (const s of selection) { - if (s?.["value"]) { - filterFromRemoteByValue.call(self, url, s?.["value"]); - } - } - - }, 100); - + const self = this; + + setTimeout(() => { + const selection = self.getOption("selection"); + if (selection.length === 0) { + return; + } + + if (self[isLoadingSymbol] === true) { + return; + } + + if (self[lazyLoadDoneSymbol] === true) { + return; + } + + let url = self.getOption("url"); + let lookupUrl = self.getOption("lookup.url"); + if (lookupUrl !== null) { + url = lookupUrl; + } + + if (this.getOption("lookup.grouping") === true) { + filterFromRemoteByValue.call( + self, + url, + selection.map((s) => s?.["value"]), + ); + return; + } + + for (const s of selection) { + if (s?.["value"]) { + filterFromRemoteByValue.call(self, url, s?.["value"]); + } + } + }, 100); } /** @@ -878,64 +874,64 @@ function lookupSelection() { * @return {object} */ function initOptionsFromArguments() { - const options = {}; - - const template = this.getAttribute("data-monster-selected-template"); - if (isString(template)) { - if (!options["templateMapping"]) options["templateMapping"] = {}; - - switch (template) { - case "summary": - case "default": - options["templateMapping"]["selected"] = getSummaryTemplate(); - break; - case "selected": - options["templateMapping"]["selected"] = getSelectionTemplate(); - break; - default: - addAttributeToken( - this, - ATTRIBUTE_ERRORMESSAGE, - "invalid template, use summary or selected", - ); - } - } - - return options; + const options = {}; + + const template = this.getAttribute("data-monster-selected-template"); + if (isString(template)) { + if (!options["templateMapping"]) options["templateMapping"] = {}; + + switch (template) { + case "summary": + case "default": + options["templateMapping"]["selected"] = getSummaryTemplate(); + break; + case "selected": + options["templateMapping"]["selected"] = getSelectionTemplate(); + break; + default: + addAttributeToken( + this, + ATTRIBUTE_ERRORMESSAGE, + "invalid template, use summary or selected", + ); + } + } + + return options; } /** * @private */ function attachResizeObserver() { - // against flickering - this[resizeObserverSymbol] = new ResizeObserver((entries) => { - if (this[timerCallbackSymbol] instanceof DeadMansSwitch) { - try { - this[timerCallbackSymbol].touch(); - return; - } catch (e) { - delete this[timerCallbackSymbol]; - } - } - - this[timerCallbackSymbol] = new DeadMansSwitch(200, () => { - updatePopper.call(this); - delete this[timerCallbackSymbol]; - }); - }); - - this[resizeObserverSymbol].observe(this.parentElement); + // against flickering + this[resizeObserverSymbol] = new ResizeObserver((entries) => { + if (this[timerCallbackSymbol] instanceof DeadMansSwitch) { + try { + this[timerCallbackSymbol].touch(); + return; + } catch (e) { + delete this[timerCallbackSymbol]; + } + } + + this[timerCallbackSymbol] = new DeadMansSwitch(200, () => { + updatePopper.call(this); + delete this[timerCallbackSymbol]; + }); + }); + + this[resizeObserverSymbol].observe(this.parentElement); } function disconnectResizeObserver() { - if (this[resizeObserverSymbol] instanceof ResizeObserver) { - this[resizeObserverSymbol].disconnect(); - } + if (this[resizeObserverSymbol] instanceof ResizeObserver) { + this[resizeObserverSymbol].disconnect(); + } } function getSelectionTemplate() { - return `<div data-monster-role="selection" + return `<div data-monster-role="selection" data-monster-insert="selection path:selection" role="search" ><input type="text" role="searchbox" part="inline-filter" name="inline-filter" @@ -947,7 +943,7 @@ function getSelectionTemplate() { } function getSummaryTemplate() { - return `<div data-monster-role="selection" role="search"> + return `<div data-monster-role="selection" role="search"> <input type="text" role="searchbox" part="inline-filter" name="inline-filter" data-monster-role="filter" @@ -963,35 +959,35 @@ function getSummaryTemplate() { * @private */ function parseSlotsToOptions() { - let options = this.getOption("options"); - if (!isIterable(options)) { - options = []; - } - - let counter = 1; - getSlottedElements.call(this, "div").forEach((node) => { - let value = (counter++).toString(); - let visibility = "visible"; - - if (node.hasAttribute("data-monster-value")) { - value = node.getAttribute("data-monster-value"); - } - - if (node.style.display === "none") { - visibility = "hidden"; - } - - const label = node.outerHTML; - - options.push({ - value, - label, - visibility, - }); - }); - - runAsOptionLengthChanged.call(this, options.length); - this.setOption("options", options); + let options = this.getOption("options"); + if (!isIterable(options)) { + options = []; + } + + let counter = 1; + getSlottedElements.call(this, "div").forEach((node) => { + let value = (counter++).toString(); + let visibility = "visible"; + + if (node.hasAttribute("data-monster-value")) { + value = node.getAttribute("data-monster-value"); + } + + if (node.style.display === "none") { + visibility = "hidden"; + } + + const label = node.outerHTML; + + options.push({ + value, + label, + visibility, + }); + }); + + runAsOptionLengthChanged.call(this, options.length); + this.setOption("options", options); } /** @@ -1001,39 +997,39 @@ function parseSlotsToOptions() { * @param {int} targetLength */ function runAsOptionLengthChanged(targetLength) { - const self = this; - - if (!self[optionsElementSymbol]) { - return; - } - - const callback = function (mutationsList, observer) { - const run = false; - for (const mutation of mutationsList) { - if (mutation.type === "childList") { - const run = true; - break; - } - } - - if (run === true) { - const nodes = self[optionsElementSymbol].querySelectorAll( - `div[${ATTRIBUTE_ROLE}=option]`, - ); - - if (nodes.length === targetLength) { - checkOptionState.call(self); - observer.disconnect(); - } - } - }; - - const observer = new MutationObserver(callback); - observer.observe(self[optionsElementSymbol], { - attributes: false, - childList: true, - subtree: true, - }); + const self = this; + + if (!self[optionsElementSymbol]) { + return; + } + + const callback = function (mutationsList, observer) { + const run = false; + for (const mutation of mutationsList) { + if (mutation.type === "childList") { + const run = true; + break; + } + } + + if (run === true) { + const nodes = self[optionsElementSymbol].querySelectorAll( + `div[${ATTRIBUTE_ROLE}=option]`, + ); + + if (nodes.length === targetLength) { + checkOptionState.call(self); + observer.disconnect(); + } + } + }; + + const observer = new MutationObserver(callback); + observer.observe(self[optionsElementSymbol], { + attributes: false, + childList: true, + subtree: true, + }); } /** @@ -1042,38 +1038,38 @@ function runAsOptionLengthChanged(targetLength) { * @return {*} */ function buildSelectionLabel(value) { - const options = this.getOption("options"); - - for (let i = 0; i < options.length; i++) { - let o = options?.[i]; - let l, v, v2; - - if (this.getOption("features.useStrictValueComparison") === true) { - v = value; - } else { - v = `${value}`; - } - - if (isPrimitive(o) && o === value) { - return o; - } else if (!isObject(o)) { - continue; - } - - if (this.getOption("features.useStrictValueComparison") === true) { - l = o?.["label"]; - v2 = o?.["value"]; - } else { - l = `${o?.["label"]}`; - v2 = `${o?.["value"]}`; - } - - if (v2 === v) { - return l; - } - } - - return undefined; + const options = this.getOption("options"); + + for (let i = 0; i < options.length; i++) { + let o = options?.[i]; + let l, v, v2; + + if (this.getOption("features.useStrictValueComparison") === true) { + v = value; + } else { + v = `${value}`; + } + + if (isPrimitive(o) && o === value) { + return o; + } else if (!isObject(o)) { + continue; + } + + if (this.getOption("features.useStrictValueComparison") === true) { + l = o?.["label"]; + v2 = o?.["value"]; + } else { + l = `${o?.["label"]}`; + v2 = `${o?.["value"]}`; + } + + if (v2 === v) { + return l; + } + } + + return undefined; } /** @@ -1083,17 +1079,17 @@ function buildSelectionLabel(value) { * @throws {Error} no value found */ function getSelectionLabel(value) { - const callback = this.getOption("formatter.selection"); - if (isFunction(callback)) { - const label = callback.call(this, value); - if (isString(label)) return label; - } + const callback = this.getOption("formatter.selection"); + if (isFunction(callback)) { + const label = callback.call(this, value); + if (isString(label)) return label; + } - if (isString(value) || isInteger(value)) { - return `${value}`; - } + if (isString(value) || isInteger(value)) { + return `${value}`; + } - return this.getOption("labels.cannot-be-loaded", value); + return this.getOption("labels.cannot-be-loaded", value); } /** @@ -1101,25 +1097,25 @@ function getSelectionLabel(value) { * @param {Event} event */ function handleToggleKeyboardEvents(event) { - switch (event?.["code"]) { - case "Escape": - toggle.call(this); - event.preventDefault(); - break; - case "Space": - toggle.call(this); - event.preventDefault(); - break; - case "ArrowDown": - show.call(this); - activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN); - event.preventDefault(); - break; - case "ArrowUp": - hide.call(this); - event.preventDefault(); - break; - } + switch (event?.["code"]) { + case "Escape": + toggle.call(this); + event.preventDefault(); + break; + case "Space": + toggle.call(this); + event.preventDefault(); + break; + case "ArrowDown": + show.call(this); + activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN); + event.preventDefault(); + break; + case "ArrowUp": + hide.call(this); + event.preventDefault(); + break; + } } /** @@ -1129,46 +1125,45 @@ function handleToggleKeyboardEvents(event) { * @this CustomElement */ function initOptionObserver() { - const self = this; - - self.attachObserver( - new Observer(function () { - new Processing(() => { - try { - self.updateI18n(); - } catch (e) { - console.error(e); - requestAnimationFrame(() => { - setStatusOrRemoveBadges.call(self, "error"); - }); - } - try { - areOptionsAvailableAndInit.call(self); - } catch (e) { - console.error(e); - requestAnimationFrame(() => { - setStatusOrRemoveBadges.call(self, "error"); - }); - } - - setSummaryAndControlText.call(self); - }).run(); - }), - ); + const self = this; + + self.attachObserver( + new Observer(function () { + new Processing(() => { + try { + self.updateI18n(); + } catch (e) { + console.error(e); + requestAnimationFrame(() => { + setStatusOrRemoveBadges.call(self, "error"); + }); + } + try { + areOptionsAvailableAndInit.call(self); + } catch (e) { + console.error(e); + requestAnimationFrame(() => { + setStatusOrRemoveBadges.call(self, "error"); + }); + } + + setSummaryAndControlText.call(self); + }).run(); + }), + ); } function getDefaultTranslation() { - const translation = new Translations("en").assignTranslations( - this.getOption("labels", {}), - ); + const translation = new Translations("en").assignTranslations( + this.getOption("labels", {}), + ); - try { - const doc = getDocumentTranslations(); - translation.locale = doc.locale; - } catch (e) { - } + try { + const doc = getDocumentTranslations(); + translation.locale = doc.locale; + } catch (e) {} - return translation; + return translation; } /** @@ -1176,36 +1171,36 @@ function getDefaultTranslation() { * @returns {string|*} */ function setSummaryAndControlText() { - const translations = getDefaultTranslation.call(this); - const selections = this.getOption("selection"); - - const text = translations.getPluralRuleText( - "summary-text", - selections.length, - "", - ); - - const selectedText = new Formatter({ - count: String(selections.length), - }).format(text); - - this.setOption("messages.selected", selectedText); - - const current = this.getOption("messages.control"); - const msg = this.getOption("labels.select-an-option"); - - if ( - current === "" || - current === undefined || - current === msg || - current === null - ) { - if (selections === undefined || selections.length === 0) { - this.setOption("messages.control", msg); - } else { - this.setOption("messages.control", ""); - } - } + const translations = getDefaultTranslation.call(this); + const selections = this.getOption("selection"); + + const text = translations.getPluralRuleText( + "summary-text", + selections.length, + "", + ); + + const selectedText = new Formatter({ + count: String(selections.length), + }).format(text); + + this.setOption("messages.selected", selectedText); + + const current = this.getOption("messages.control"); + const msg = this.getOption("labels.select-an-option"); + + if ( + current === "" || + current === undefined || + current === msg || + current === null + ) { + if (selections === undefined || selections.length === 0) { + this.setOption("messages.control", msg); + } else { + this.setOption("messages.control", ""); + } + } } /** @@ -1213,9 +1208,9 @@ function setSummaryAndControlText() { * @return {NodeList} */ function getOptionElements() { - return this[optionsElementSymbol].querySelectorAll( - `[${ATTRIBUTE_ROLE}=option]`, - ); + return this[optionsElementSymbol].querySelectorAll( + `[${ATTRIBUTE_ROLE}=option]`, + ); } /** @@ -1241,82 +1236,82 @@ function getOptionElements() { * @private */ function calcAndSetOptionsDimension() { - const options = getOptionElements.call(this); - const container = this[optionsElementSymbol]; - if (!(container instanceof HTMLElement && options instanceof NodeList)) { - return; - } - - let visible = 0; - let optionHeight = 0; - const max = this.getOption("showMaxOptions", 10); - - let scrollFlag = false; - for (const [, option] of Object.entries(options)) { - const computedStyle = getGlobal().getComputedStyle(option); - if (computedStyle.display === "none") continue; - - let h = option.getBoundingClientRect().height; - h += parseInt(computedStyle.getPropertyValue("margin-top"), 10); - h += parseInt(computedStyle.getPropertyValue("margin-bottom"), 10); - optionHeight += h; - - visible++; - - if (visible > max) { - break; - } - } - - if (visible > max) { - visible = max; - scrollFlag = true; - } - - if (visible === 0) { - if (this.getOption("options").length === 0) { - this.setOption( - "messages.emptyOptions", - this.getOption("labels.no-options-available"), - ); - } else { - if (this.getOption("filter.mode") === FILTER_MODE_DISABLED) { - this.setOption( - "messages.emptyOptions", - this.getOption("labels.no-options-available"), - ); - } else { - this.setOption( - "messages.emptyOptions", - this.getOption("labels.no-options-found"), - ); - } - } - this[noOptionsAvailableElementSymbol].classList.remove("d-none"); - } else { - this[noOptionsAvailableElementSymbol].classList.add("d-none"); - } - - const styles = getGlobal().getComputedStyle(this[optionsElementSymbol]); - let padding = parseInt(styles.getPropertyValue("padding-top"), 10); - padding += parseInt(styles.getPropertyValue("padding-bottom"), 10); - - let margin = parseInt(styles.getPropertyValue("margin-top"), 10); - margin += parseInt(styles.getPropertyValue("margin-bottom"), 10); - - const containerHeight = optionHeight + padding + margin; - container.style.height = `${containerHeight}px`; - - if (scrollFlag === true) { - container.style.overflowY = "scroll"; - } else { - container.style.overflowY = "auto"; - } - - const domRect = this[controlElementSymbol].getBoundingClientRect(); - - this[popperElementSymbol].style.width = `${domRect.width}px`; - container.style.overflowX = "auto"; + const options = getOptionElements.call(this); + const container = this[optionsElementSymbol]; + if (!(container instanceof HTMLElement && options instanceof NodeList)) { + return; + } + + let visible = 0; + let optionHeight = 0; + const max = this.getOption("showMaxOptions", 10); + + let scrollFlag = false; + for (const [, option] of Object.entries(options)) { + const computedStyle = getGlobal().getComputedStyle(option); + if (computedStyle.display === "none") continue; + + let h = option.getBoundingClientRect().height; + h += parseInt(computedStyle.getPropertyValue("margin-top"), 10); + h += parseInt(computedStyle.getPropertyValue("margin-bottom"), 10); + optionHeight += h; + + visible++; + + if (visible > max) { + break; + } + } + + if (visible > max) { + visible = max; + scrollFlag = true; + } + + if (visible === 0) { + if (this.getOption("options").length === 0) { + this.setOption( + "messages.emptyOptions", + this.getOption("labels.no-options-available"), + ); + } else { + if (this.getOption("filter.mode") === FILTER_MODE_DISABLED) { + this.setOption( + "messages.emptyOptions", + this.getOption("labels.no-options-available"), + ); + } else { + this.setOption( + "messages.emptyOptions", + this.getOption("labels.no-options-found"), + ); + } + } + this[noOptionsAvailableElementSymbol].classList.remove("d-none"); + } else { + this[noOptionsAvailableElementSymbol].classList.add("d-none"); + } + + const styles = getGlobal().getComputedStyle(this[optionsElementSymbol]); + let padding = parseInt(styles.getPropertyValue("padding-top"), 10); + padding += parseInt(styles.getPropertyValue("padding-bottom"), 10); + + let margin = parseInt(styles.getPropertyValue("margin-top"), 10); + margin += parseInt(styles.getPropertyValue("margin-bottom"), 10); + + const containerHeight = optionHeight + padding + margin; + container.style.height = `${containerHeight}px`; + + if (scrollFlag === true) { + container.style.overflowY = "scroll"; + } else { + container.style.overflowY = "auto"; + } + + const domRect = this[controlElementSymbol].getBoundingClientRect(); + + this[popperElementSymbol].style.width = `${domRect.width}px`; + container.style.overflowX = "auto"; } /** @@ -1325,126 +1320,126 @@ function calcAndSetOptionsDimension() { * @throws {Error} no shadow-root is defined */ function activateCurrentOption(direction) { - if (!this.shadowRoot) { - throw new Error("no shadow-root is defined"); - } - - let focused = this.shadowRoot.querySelector(`[${ATTRIBUTE_PREFIX}focused]`); - - if ( - !(focused instanceof HTMLElement) || - focused.matches("[data-monster-visibility=hidden]") - ) { - for (const [, e] of Object.entries( - this.shadowRoot.querySelectorAll(`[${ATTRIBUTE_ROLE}=option]`), - )) { - if (e.matches("[data-monster-visibility=visible]")) { - focused = e; - break; - } - } - } else { - if (direction === FOCUS_DIRECTION_DOWN) { - while (focused.nextSibling) { - focused = focused.nextSibling; - - if ( - focused instanceof HTMLElement && - focused.hasAttribute(ATTRIBUTE_ROLE) && - focused.getAttribute(ATTRIBUTE_ROLE) === "option" && - focused.matches("[data-monster-visibility=visible]") && - focused.matches(":not([data-monster-filtered=true])") - ) { - break; - } - } - } else { - let found = false; - while (focused.previousSibling) { - focused = focused.previousSibling; - if ( - focused instanceof HTMLElement && - focused.hasAttribute(ATTRIBUTE_ROLE) && - focused.getAttribute(ATTRIBUTE_ROLE) === "option" && - focused.matches("[data-monster-visibility=visible]") && - focused.matches(":not([data-monster-filtered=true])") - ) { - found = true; - break; - } - } - if (found === false) { - focusFilter.call(this); - } - } - } - - new Processing(() => { - if (focused instanceof HTMLElement) { - this.shadowRoot - .querySelectorAll(`[${ATTRIBUTE_PREFIX}focused]`) - .forEach((e) => { - e.removeAttribute(`${ATTRIBUTE_PREFIX}focused`); - }); - - focused.focus(); - focused.setAttribute(`${ATTRIBUTE_PREFIX}focused`, true); - } - }) - .run() - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - }); + if (!this.shadowRoot) { + throw new Error("no shadow-root is defined"); + } + + let focused = this.shadowRoot.querySelector(`[${ATTRIBUTE_PREFIX}focused]`); + + if ( + !(focused instanceof HTMLElement) || + focused.matches("[data-monster-visibility=hidden]") + ) { + for (const [, e] of Object.entries( + this.shadowRoot.querySelectorAll(`[${ATTRIBUTE_ROLE}=option]`), + )) { + if (e.matches("[data-monster-visibility=visible]")) { + focused = e; + break; + } + } + } else { + if (direction === FOCUS_DIRECTION_DOWN) { + while (focused.nextSibling) { + focused = focused.nextSibling; + + if ( + focused instanceof HTMLElement && + focused.hasAttribute(ATTRIBUTE_ROLE) && + focused.getAttribute(ATTRIBUTE_ROLE) === "option" && + focused.matches("[data-monster-visibility=visible]") && + focused.matches(":not([data-monster-filtered=true])") + ) { + break; + } + } + } else { + let found = false; + while (focused.previousSibling) { + focused = focused.previousSibling; + if ( + focused instanceof HTMLElement && + focused.hasAttribute(ATTRIBUTE_ROLE) && + focused.getAttribute(ATTRIBUTE_ROLE) === "option" && + focused.matches("[data-monster-visibility=visible]") && + focused.matches(":not([data-monster-filtered=true])") + ) { + found = true; + break; + } + } + if (found === false) { + focusFilter.call(this); + } + } + } + + new Processing(() => { + if (focused instanceof HTMLElement) { + this.shadowRoot + .querySelectorAll(`[${ATTRIBUTE_PREFIX}focused]`) + .forEach((e) => { + e.removeAttribute(`${ATTRIBUTE_PREFIX}focused`); + }); + + focused.focus(); + focused.setAttribute(`${ATTRIBUTE_PREFIX}focused`, true); + } + }) + .run() + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + }); } /** * @private */ function filterOptions() { - new Processing(() => { - let filterValue; - - switch (this.getOption("filter.position")) { - case FILTER_POSITION_INLINE: - if (this[inlineFilterElementSymbol] instanceof HTMLElement) { - filterValue = this[inlineFilterElementSymbol].value.toLowerCase(); - } else { - return; - } - - break; - case FILTER_POSITION_POPPER: - default: - if (this[popperFilterElementSymbol] instanceof HTMLInputElement) { - filterValue = this[popperFilterElementSymbol].value.toLowerCase(); - } else { - return; - } - } - - const options = this.getOption("options"); - for (const [i, option] of Object.entries(options)) { - if (option.label.toLowerCase().indexOf(filterValue) === -1) { - this.setOption(`options.${i}.filtered`, "true"); - } else { - this.setOption(`options.${i}.filtered`, undefined); - } - } - }) - .run() - .then(() => { - new Processing(100, () => { - calcAndSetOptionsDimension.call(this); - focusFilter.call(this); - }) - .run() - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - }); - }) - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - }); + new Processing(() => { + let filterValue; + + switch (this.getOption("filter.position")) { + case FILTER_POSITION_INLINE: + if (this[inlineFilterElementSymbol] instanceof HTMLElement) { + filterValue = this[inlineFilterElementSymbol].value.toLowerCase(); + } else { + return; + } + + break; + case FILTER_POSITION_POPPER: + default: + if (this[popperFilterElementSymbol] instanceof HTMLInputElement) { + filterValue = this[popperFilterElementSymbol].value.toLowerCase(); + } else { + return; + } + } + + const options = this.getOption("options"); + for (const [i, option] of Object.entries(options)) { + if (option.label.toLowerCase().indexOf(filterValue) === -1) { + this.setOption(`options.${i}.filtered`, "true"); + } else { + this.setOption(`options.${i}.filtered`, undefined); + } + } + }) + .run() + .then(() => { + new Processing(100, () => { + calcAndSetOptionsDimension.call(this); + focusFilter.call(this); + }) + .run() + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + }); + }) + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + }); } /** @@ -1452,37 +1447,37 @@ function filterOptions() { * @param {Event} event */ function handleFilterKeyboardEvents(event) { - const shiftKey = event?.["shiftKey"]; - - switch (event?.["code"]) { - case "Tab": - activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN); - event.preventDefault(); - break; - case "Escape": - toggle.call(this); - event.preventDefault(); - break; - case "Tab" && shiftKey === true: - case "ArrowUp": - activateCurrentOption.call(this, FOCUS_DIRECTION_UP); - event.preventDefault(); - break; - case "Tab" && !shiftKey: - case "ArrowDown": - activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN); - event.preventDefault(); - break; - default: - if ( - this.getOption("features.lazyLoad") === true && - this[lazyLoadDoneSymbol] !== true - ) { - this.click(); - } - - handleFilterKeyEvents.call(this); - } + const shiftKey = event?.["shiftKey"]; + + switch (event?.["code"]) { + case "Tab": + activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN); + event.preventDefault(); + break; + case "Escape": + toggle.call(this); + event.preventDefault(); + break; + case "Tab" && shiftKey === true: + case "ArrowUp": + activateCurrentOption.call(this, FOCUS_DIRECTION_UP); + event.preventDefault(); + break; + case "Tab" && !shiftKey: + case "ArrowDown": + activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN); + event.preventDefault(); + break; + default: + if ( + this.getOption("features.lazyLoad") === true && + this[lazyLoadDoneSymbol] !== true + ) { + this.click(); + } + + handleFilterKeyEvents.call(this); + } } /** @@ -1501,85 +1496,83 @@ function handleFilterKeyboardEvents(event) { * @returns {void} This method does not return anything. */ function handleFilterKeyEvents() { - if (this[keyFilterEventSymbol] instanceof DeadMansSwitch) { - try { - this[keyFilterEventSymbol].touch(); - return; - } catch (e) { - delete this[keyFilterEventSymbol]; - } - } - - this[keyFilterEventSymbol] = new DeadMansSwitch(200, () => { - if (this.getOption("filter.mode") !== FILTER_MODE_REMOTE) { - filterOptions.call(this); - } else { - filterFromRemote.call(this).catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - }); - } - - delete this[keyFilterEventSymbol]; - }); + if (this[keyFilterEventSymbol] instanceof DeadMansSwitch) { + try { + this[keyFilterEventSymbol].touch(); + return; + } catch (e) { + delete this[keyFilterEventSymbol]; + } + } + + this[keyFilterEventSymbol] = new DeadMansSwitch(200, () => { + if (this.getOption("filter.mode") !== FILTER_MODE_REMOTE) { + filterOptions.call(this); + } else { + filterFromRemote.call(this).catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + }); + } + + delete this[keyFilterEventSymbol]; + }); } /** * @private */ function filterFromRemote() { - if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) { - return; - } - - const optionUrl = this.getOption("url"); - if (!optionUrl) { - addAttributeToken( - this, - ATTRIBUTE_ERRORMESSAGE, - "Missing URL for Remote Filter.", - ); - return; - } - - - return filterFromRemoteByValue.call(this, optionUrl, this[inlineFilterElementSymbol].value); - + if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) { + return; + } + + const optionUrl = this.getOption("url"); + if (!optionUrl) { + addAttributeToken( + this, + ATTRIBUTE_ERRORMESSAGE, + "Missing URL for Remote Filter.", + ); + return; + } + + return filterFromRemoteByValue.call( + this, + optionUrl, + this[inlineFilterElementSymbol].value, + ); } /** * @private */ function filterFromRemoteByValue(optionUrl, value) { - - return new Processing(() => { - const filterValue = encodeURI( - value - ); - let url = optionUrl; - if (filterValue.length > 0) { - - const formatter = new Formatter({filter: filterValue}); - const openMarker = this.getOption("filter.marker.open"); - let closeMarker = this.getOption("filter.marker.close"); - if (!closeMarker) { - closeMarker = openMarker; - } - - if (openMarker && closeMarker) { - formatter.setMarker(openMarker, closeMarker); - } - - url = formatter.format(optionUrl); - } - - this.fetch(url) - .then(() => { - checkOptionState.call(this); - }) - .catch((e) => { - throw e; - }); - }).run(); + return new Processing(() => { + const filterValue = encodeURI(value); + let url = optionUrl; + if (filterValue.length > 0) { + const formatter = new Formatter({ filter: filterValue }); + const openMarker = this.getOption("filter.marker.open"); + let closeMarker = this.getOption("filter.marker.close"); + if (!closeMarker) { + closeMarker = openMarker; + } + + if (openMarker && closeMarker) { + formatter.setMarker(openMarker, closeMarker); + } + + url = formatter.format(optionUrl); + } + + this.fetch(url) + .then(() => { + checkOptionState.call(this); + }) + .catch((e) => { + throw e; + }); + }).run(); } /** @@ -1588,50 +1581,50 @@ function filterFromRemoteByValue(optionUrl, value) { * @private */ function handleOptionKeyboardEvents(event) { - const shiftKey = event?.["shiftKey"]; - - switch (event?.["code"]) { - case "Escape": - toggle.call(this); - event.preventDefault(); - break; - case "Enter": - case "Space": - const path = event.composedPath(); - const element = path?.[0]; - if (element instanceof HTMLElement) { - const input = element.getElementsByTagName("input"); - if (!input) { - return; - } - fireEvent(input, "click"); - } - event.preventDefault(); - break; - - case "Tab" && shiftKey === true: - case "ArrowUp": - activateCurrentOption.call(this, FOCUS_DIRECTION_UP); - event.preventDefault(); - break; - - case "Tab" && !shiftKey: - case "ArrowLeft": - case "ArrowRight": - // handled by tree select - break; - case "ArrowDown": - activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN); - event.preventDefault(); - break; - default: - const p = event.composedPath(); - if (p?.[0] instanceof HTMLInputElement) { - return; - } - focusFilter.call(this); - break; - } + const shiftKey = event?.["shiftKey"]; + + switch (event?.["code"]) { + case "Escape": + toggle.call(this); + event.preventDefault(); + break; + case "Enter": + case "Space": + const path = event.composedPath(); + const element = path?.[0]; + if (element instanceof HTMLElement) { + const input = element.getElementsByTagName("input"); + if (!input) { + return; + } + fireEvent(input, "click"); + } + event.preventDefault(); + break; + + case "Tab" && shiftKey === true: + case "ArrowUp": + activateCurrentOption.call(this, FOCUS_DIRECTION_UP); + event.preventDefault(); + break; + + case "Tab" && !shiftKey: + case "ArrowLeft": + case "ArrowRight": + // handled by tree select + break; + case "ArrowDown": + activateCurrentOption.call(this, FOCUS_DIRECTION_DOWN); + event.preventDefault(); + break; + default: + const p = event.composedPath(); + if (p?.[0] instanceof HTMLInputElement) { + return; + } + focusFilter.call(this); + break; + } } /** @@ -1639,33 +1632,33 @@ function handleOptionKeyboardEvents(event) { * @returns {string} */ function getFilterMode() { - switch (this.getOption("filter.mode")) { - case FILTER_MODE_OPTIONS: - return FILTER_MODE_OPTIONS; - case FILTER_MODE_REMOTE: - return FILTER_MODE_REMOTE; - default: - return FILTER_MODE_DISABLED; - } + switch (this.getOption("filter.mode")) { + case FILTER_MODE_OPTIONS: + return FILTER_MODE_OPTIONS; + case FILTER_MODE_REMOTE: + return FILTER_MODE_REMOTE; + default: + return FILTER_MODE_DISABLED; + } } /** * @private */ function blurFilter() { - if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) { - return; - } + if (!(this[inlineFilterElementSymbol] instanceof HTMLElement)) { + return; + } - if (getFilterMode.call(this) === FILTER_MODE_DISABLED) { - return; - } + if (getFilterMode.call(this) === FILTER_MODE_DISABLED) { + return; + } - this[popperFilterContainerElementSymbol].classList.remove("active"); - this[popperFilterContainerElementSymbol].blur(); + this[popperFilterContainerElementSymbol].classList.remove("active"); + this[popperFilterContainerElementSymbol].blur(); - this[inlineFilterElementSymbol].classList.remove("active"); - this[inlineFilterElementSymbol].blur(); + this[inlineFilterElementSymbol].classList.remove("active"); + this[inlineFilterElementSymbol].blur(); } /** @@ -1673,29 +1666,29 @@ function blurFilter() { * @param focusOptions */ function focusPopperFilter(focusOptions) { - this[popperFilterContainerElementSymbol].classList.remove("d-none"); - this[popperFilterElementSymbol].classList.add("active"); - this[inlineFilterElementSymbol].classList.remove("active"); - this[inlineFilterElementSymbol].classList.add("d-none"); - - if (!(this[popperFilterElementSymbol] instanceof HTMLElement)) { - addAttributeToken( - this, - ATTRIBUTE_ERRORMESSAGE, - "Missing Popper Filter Element.", - ); - return; - } - - // visibility is set to visible, because focus() does not work on invisible elements - // and the class definition is assigned later in the processing - setTimeout(() => { - if (focusOptions === undefined || focusOptions === null) { - this[popperFilterElementSymbol].focus(); - } else { - this[popperFilterElementSymbol].focus(focusOptions); - } - }, 100); + this[popperFilterContainerElementSymbol].classList.remove("d-none"); + this[popperFilterElementSymbol].classList.add("active"); + this[inlineFilterElementSymbol].classList.remove("active"); + this[inlineFilterElementSymbol].classList.add("d-none"); + + if (!(this[popperFilterElementSymbol] instanceof HTMLElement)) { + addAttributeToken( + this, + ATTRIBUTE_ERRORMESSAGE, + "Missing Popper Filter Element.", + ); + return; + } + + // visibility is set to visible, because focus() does not work on invisible elements + // and the class definition is assigned later in the processing + setTimeout(() => { + if (focusOptions === undefined || focusOptions === null) { + this[popperFilterElementSymbol].focus(); + } else { + this[popperFilterElementSymbol].focus(focusOptions); + } + }, 100); } /** @@ -1703,44 +1696,44 @@ function focusPopperFilter(focusOptions) { * @param focusOptions */ function focusInlineFilter(focusOptions) { - const options = this.getOption("options"); - if ( - (!isArray(options) || options.length === 0) && - this.getOption("filter.mode") !== FILTER_MODE_REMOTE - ) { - return; - } - - this[popperFilterContainerElementSymbol].classList.add("d-none"); - this[inlineFilterElementSymbol].classList.add("active"); - this[inlineFilterElementSymbol].classList.remove("d-none"); - - // visibility is set to visible, because focus() does not work on invisible elements - // and the class definition is assigned later in the processing - setTimeout(() => { - if (focusOptions === undefined || focusOptions === null) { - this[inlineFilterElementSymbol].focus(); - } else { - this[inlineFilterElementSymbol].focus(focusOptions); - } - }, 100); + const options = this.getOption("options"); + if ( + (!isArray(options) || options.length === 0) && + this.getOption("filter.mode") !== FILTER_MODE_REMOTE + ) { + return; + } + + this[popperFilterContainerElementSymbol].classList.add("d-none"); + this[inlineFilterElementSymbol].classList.add("active"); + this[inlineFilterElementSymbol].classList.remove("d-none"); + + // visibility is set to visible, because focus() does not work on invisible elements + // and the class definition is assigned later in the processing + setTimeout(() => { + if (focusOptions === undefined || focusOptions === null) { + this[inlineFilterElementSymbol].focus(); + } else { + this[inlineFilterElementSymbol].focus(focusOptions); + } + }, 100); } /** * @private */ function focusFilter(focusOptions) { - if (getFilterMode.call(this) === FILTER_MODE_DISABLED) { - this[popperFilterContainerElementSymbol].classList.add("d-none"); - this[inlineFilterElementSymbol].classList.add("d-none"); - return; - } + if (getFilterMode.call(this) === FILTER_MODE_DISABLED) { + this[popperFilterContainerElementSymbol].classList.add("d-none"); + this[inlineFilterElementSymbol].classList.add("d-none"); + return; + } - if (this.getOption("filter.position") === FILTER_POSITION_INLINE) { - return focusInlineFilter.call(this, focusOptions); - } + if (this.getOption("filter.position") === FILTER_POSITION_INLINE) { + return focusInlineFilter.call(this, focusOptions); + } - return focusPopperFilter.call(this, focusOptions); + return focusPopperFilter.call(this, focusOptions); } /** @@ -1750,40 +1743,39 @@ function focusFilter(focusOptions) { * @throws {Error} unsupported type */ function gatherState() { - const type = this.getOption("type"); - if (["radio", "checkbox"].indexOf(type) === -1) { - throw new Error("unsupported type"); - } - - if (!this.shadowRoot) { - throw new Error("no shadow-root is defined"); - } - - const selection = []; - const elements = this.shadowRoot.querySelectorAll( - `input[type=${type}]:checked`, - ); - - for (const e of elements) { - selection.push({ - label: getSelectionLabel.call(this, e.value), - value: e.value, - }); - } - - setSelection - .call(this, selection) - .then(() => { - }) - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); - }); - - if (this.getOption("features.closeOnSelect") === true) { - toggle.call(this); - } - - return this; + const type = this.getOption("type"); + if (["radio", "checkbox"].indexOf(type) === -1) { + throw new Error("unsupported type"); + } + + if (!this.shadowRoot) { + throw new Error("no shadow-root is defined"); + } + + const selection = []; + const elements = this.shadowRoot.querySelectorAll( + `input[type=${type}]:checked`, + ); + + for (const e of elements) { + selection.push({ + label: getSelectionLabel.call(this, e.value), + value: e.value, + }); + } + + setSelection + .call(this, selection) + .then(() => {}) + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); + }); + + if (this.getOption("features.closeOnSelect") === true) { + toggle.call(this); + } + + return this; } /** @@ -1792,121 +1784,120 @@ function gatherState() { * @throws {Error} unsupported type */ function clearSelection() { - const type = this.getOption("type"); - if (["radio", "checkbox"].indexOf(type) === -1) { - throw new Error("unsupported type"); - } - - if (!this.shadowRoot) { - throw new Error("no shadow-root is defined"); - } - - setSelection - .call(this, []) - .then(() => { - }) - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); - }); + const type = this.getOption("type"); + if (["radio", "checkbox"].indexOf(type) === -1) { + throw new Error("unsupported type"); + } + + if (!this.shadowRoot) { + throw new Error("no shadow-root is defined"); + } + + setSelection + .call(this, []) + .then(() => {}) + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); + }); } /** * @private */ function areOptionsAvailableAndInit() { - // prevent multiple calls - if (this[areOptionsAvailableAndInitSymbol] === undefined) { - this[areOptionsAvailableAndInitSymbol] = 0; - } - - if (this[areOptionsAvailableAndInitSymbol] > 0) { - this[areOptionsAvailableAndInitSymbol]--; - return true; - } - - this[areOptionsAvailableAndInitSymbol]++; - - const options = this.getOption("options"); - - if ( - options === undefined || - options === null || - (isArray(options) && options.length === 0) - ) { - setStatusOrRemoveBadges.call(this, "empty"); - - hide.call(this); - - let msg = this.getOption("labels.no-options-available"); - - if ( - this.getOption("url") !== null && - this.getOption("features.lazyLoad") === true && - this[lazyLoadDoneSymbol] !== true - ) { - msg = this.getOption("labels.click-to-load-options"); - } - - this.setOption("messages.control", msg); - this.setOption("messages.summary", ""); - - if (this.getOption("features.emptyValueIfNoOptions") === true) { - this.value = ""; - } - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage); - return false; - } - - const selections = this.getOption("selection"); - if ( - selections === undefined || - selections === null || - selections.length === 0 - ) { - this.setOption( - "messages.control", - this.getOption("labels.select-an-option"), - ); - } else { - this.setOption("messages.control", ""); - } - - this.setOption("messages.summary", setSummaryAndControlText.call(this)); - - let updated = false; - let valueCounter = 1; - for (const option of options) { - if (option?.visibility === undefined) { - option.visibility = "visible"; - updated = true; - } - - if (option?.value === undefined && option?.label === undefined) { - option.value = `${valueCounter++}`; - option.label = option.value; - updated = true; - continue; - } - - if (option?.value === undefined) { - option.value = option.label; - updated = true; - } - - if (option?.label === undefined) { - option.label = option.value; - updated = true; - } - } - - if (updated) { - this.setOption("options", options); - } - - setStatusOrRemoveBadges.call(this); - - removeAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage); - return true; + // prevent multiple calls + if (this[areOptionsAvailableAndInitSymbol] === undefined) { + this[areOptionsAvailableAndInitSymbol] = 0; + } + + if (this[areOptionsAvailableAndInitSymbol] > 0) { + this[areOptionsAvailableAndInitSymbol]--; + return true; + } + + this[areOptionsAvailableAndInitSymbol]++; + + const options = this.getOption("options"); + + if ( + options === undefined || + options === null || + (isArray(options) && options.length === 0) + ) { + setStatusOrRemoveBadges.call(this, "empty"); + + hide.call(this); + + let msg = this.getOption("labels.no-options-available"); + + if ( + this.getOption("url") !== null && + this.getOption("features.lazyLoad") === true && + this[lazyLoadDoneSymbol] !== true + ) { + msg = this.getOption("labels.click-to-load-options"); + } + + this.setOption("messages.control", msg); + this.setOption("messages.summary", ""); + + if (this.getOption("features.emptyValueIfNoOptions") === true) { + this.value = ""; + } + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage); + return false; + } + + const selections = this.getOption("selection"); + if ( + selections === undefined || + selections === null || + selections.length === 0 + ) { + this.setOption( + "messages.control", + this.getOption("labels.select-an-option"), + ); + } else { + this.setOption("messages.control", ""); + } + + this.setOption("messages.summary", setSummaryAndControlText.call(this)); + + let updated = false; + let valueCounter = 1; + for (const option of options) { + if (option?.visibility === undefined) { + option.visibility = "visible"; + updated = true; + } + + if (option?.value === undefined && option?.label === undefined) { + option.value = `${valueCounter++}`; + option.label = option.value; + updated = true; + continue; + } + + if (option?.value === undefined) { + option.value = option.label; + updated = true; + } + + if (option?.label === undefined) { + option.label = option.value; + updated = true; + } + } + + if (updated) { + this.setOption("options", options); + } + + setStatusOrRemoveBadges.call(this); + + removeAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, noOptionsAvailableMessage); + return true; } /** @@ -1914,30 +1905,30 @@ function areOptionsAvailableAndInit() { * @throws {Error} no shadow-root is defined */ function checkOptionState() { - if (!this.shadowRoot) { - throw new Error("no shadow-root is defined"); - } - - const elements = this.shadowRoot.querySelectorAll( - `[${ATTRIBUTE_ROLE}=option] input`, - ); - - let selection = this.getOption("selection"); - if (!isArray(selection)) { - selection = []; - } - - const checkedValues = selection.map((a) => { - return a.value; - }); - - for (const e of elements) { - if (checkedValues.indexOf(e.value) !== -1) { - if (e.checked !== true) e.checked = true; - } else { - if (e.checked !== false) e.checked = false; - } - } + if (!this.shadowRoot) { + throw new Error("no shadow-root is defined"); + } + + const elements = this.shadowRoot.querySelectorAll( + `[${ATTRIBUTE_ROLE}=option] input`, + ); + + let selection = this.getOption("selection"); + if (!isArray(selection)) { + selection = []; + } + + const checkedValues = selection.map((a) => { + return a.value; + }); + + for (const e of elements) { + if (checkedValues.indexOf(e.value) !== -1) { + if (e.checked !== true) e.checked = true; + } else { + if (e.checked !== false) e.checked = false; + } + } } /** @@ -1946,41 +1937,41 @@ function checkOptionState() { * @return {Object} */ function convertValueToSelection(value) { - const selection = []; - - if (isString(value)) { - value = value - .split(",") - .map((a) => { - return a.trim(); - }) - .filter((a) => { - return a !== ""; - }); - } - - if (isString(value) || isInteger(value)) { - selection.push({ - label: getSelectionLabel.call(this, value), - value: value, - }); - } else if (isArray(value)) { - for (const v of value) { - selection.push({ - label: getSelectionLabel.call(this, v), - value: v, - }); - } - - value = value.join(","); - } else { - throw new Error("unsupported type"); - } - - return { - selection: selection, - value: value, - }; + const selection = []; + + if (isString(value)) { + value = value + .split(",") + .map((a) => { + return a.trim(); + }) + .filter((a) => { + return a !== ""; + }); + } + + if (isString(value) || isInteger(value)) { + selection.push({ + label: getSelectionLabel.call(this, value), + value: value, + }); + } else if (isArray(value)) { + for (const v of value) { + selection.push({ + label: getSelectionLabel.call(this, v), + value: v, + }); + } + + value = value.join(","); + } else { + throw new Error("unsupported type"); + } + + return { + selection: selection, + value: value, + }; } /** @@ -1989,22 +1980,22 @@ function convertValueToSelection(value) { * @return {string} */ function convertSelectionToValue(selection) { - const value = []; - - if (isArray(selection)) { - for (const obj of selection) { - const v = obj?.["value"]; - if (v !== undefined) value.push(v); - } - } - - if (value.length === 0) { - return ""; - } else if (value.length === 1) { - return value.pop(); - } - - return value.join(","); + const value = []; + + if (isArray(selection)) { + for (const obj of selection) { + const v = obj?.["value"]; + if (v !== undefined) value.push(v); + } + } + + if (value.length === 0) { + return ""; + } else if (value.length === 1) { + return value.pop(); + } + + return value.join(","); } /** @@ -2014,67 +2005,67 @@ function convertSelectionToValue(selection) { * @throws {Error} no shadow-root is defined */ function setSelection(selection) { - if (isString(selection)) { - const result = convertValueToSelection.call(this, selection); - selection = result?.selection; - } else if (selection === undefined) { - selection = []; - } - - validateArray(selection); - - for (let i = 0; i < selection.length; i++) { - selection[i] = { - label: getSelectionLabel.call(this, selection[i].value), - value: selection[i].value, - }; - } - - this.setOption("selection", selection); - checkOptionState.call(this); - - try { - this?.setFormValue(this.value); - } catch (e) { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - } - - fireCustomEvent(this, "monster-selected", { - selection, - }); - - return new Processing(() => { - const CLASSNAME = "selected"; - - if (!this.shadowRoot) { - throw new Error("no shadow-root is defined"); - } - - const notSelected = this.shadowRoot.querySelectorAll(":not(:checked)"); - - if (notSelected) { - notSelected.forEach((node) => { - const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`); - if (parent) { - parent.classList.remove(CLASSNAME); - } - }); - } - - const selected = this.shadowRoot.querySelectorAll(":checked"); - if (selected) { - selected.forEach((node) => { - const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`); - if (parent) { - parent.classList.add(CLASSNAME); - } - }); - } - }) - .run() - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - }); + if (isString(selection)) { + const result = convertValueToSelection.call(this, selection); + selection = result?.selection; + } else if (selection === undefined) { + selection = []; + } + + validateArray(selection); + + for (let i = 0; i < selection.length; i++) { + selection[i] = { + label: getSelectionLabel.call(this, selection[i].value), + value: selection[i].value, + }; + } + + this.setOption("selection", selection); + checkOptionState.call(this); + + try { + this?.setFormValue(this.value); + } catch (e) { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + } + + fireCustomEvent(this, "monster-selected", { + selection, + }); + + return new Processing(() => { + const CLASSNAME = "selected"; + + if (!this.shadowRoot) { + throw new Error("no shadow-root is defined"); + } + + const notSelected = this.shadowRoot.querySelectorAll(":not(:checked)"); + + if (notSelected) { + notSelected.forEach((node) => { + const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`); + if (parent) { + parent.classList.remove(CLASSNAME); + } + }); + } + + const selected = this.shadowRoot.querySelectorAll(":checked"); + if (selected) { + selected.forEach((node) => { + const parent = node.closest(`[${ATTRIBUTE_ROLE}=option]`); + if (parent) { + parent.classList.add(CLASSNAME); + } + }); + } + }) + .run() + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + }); } /** @@ -2085,138 +2076,137 @@ function setSelection(selection) { * @throws {TypeError} unsupported response */ function fetchData(url) { - const self = this; - if (!url) url = this.getOption("url"); - if (!url) return Promise.resolve(); - - const fetchOptions = this.getOption("fetch", {}); - - let delayWatch = false; - - // if fetch short time, do not show loading badge, because of flickering - requestAnimationFrame(() => { - if (delayWatch === true) return; - setStatusOrRemoveBadges.call(this, "loading"); - delayWatch = true; - }); - - url = new Formatter({filter: this.getOption("filter.defaultValue")}).format( - url, - ); - - self[isLoadingSymbol] = true; - const global = getGlobal(); - return global - .fetch(url, fetchOptions) - .then((response) => { - self[isLoadingSymbol] = false; - delayWatch = true; - const contentType = response.headers.get("content-type"); - if (contentType && contentType.indexOf("application/json") !== -1) { - return response.text(); - } - - throw new TypeError(`unsupported response ${contentType}`); - }) - .then((text) => { - try { - return Promise.resolve(JSON.parse(String(text))); - } catch (e) { - throw new TypeError("the result cannot be parsed, check the URL"); - } - }) - .catch((e) => { - self[isLoadingSymbol] = false; - delayWatch = true; - throw e; - }); + const self = this; + if (!url) url = this.getOption("url"); + if (!url) return Promise.resolve(); + + const fetchOptions = this.getOption("fetch", {}); + + let delayWatch = false; + + // if fetch short time, do not show loading badge, because of flickering + requestAnimationFrame(() => { + if (delayWatch === true) return; + setStatusOrRemoveBadges.call(this, "loading"); + delayWatch = true; + }); + + url = new Formatter({ filter: this.getOption("filter.defaultValue") }).format( + url, + ); + + self[isLoadingSymbol] = true; + const global = getGlobal(); + return global + .fetch(url, fetchOptions) + .then((response) => { + self[isLoadingSymbol] = false; + delayWatch = true; + const contentType = response.headers.get("content-type"); + if (contentType && contentType.indexOf("application/json") !== -1) { + return response.text(); + } + + throw new TypeError(`unsupported response ${contentType}`); + }) + .then((text) => { + try { + return Promise.resolve(JSON.parse(String(text))); + } catch (e) { + throw new TypeError("the result cannot be parsed, check the URL"); + } + }) + .catch((e) => { + self[isLoadingSymbol] = false; + delayWatch = true; + throw e; + }); } /** * @private */ function hide() { - this[popperElementSymbol].style.display = "none"; - setStatusOrRemoveBadges.call(this, "closed"); - removeAttributeToken(this[controlElementSymbol], "class", "open"); + this[popperElementSymbol].style.display = "none"; + setStatusOrRemoveBadges.call(this, "closed"); + removeAttributeToken(this[controlElementSymbol], "class", "open"); } /** * @private */ function show() { - if (this.getOption("disabled", undefined) === true) { - return; - } - - if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) { - return; - } - - focusFilter.call(this); - - const lazyLoadFlag = - this.getOption("features.lazyLoad") && this[lazyLoadDoneSymbol] !== true; - - if (lazyLoadFlag === true) { - this[lazyLoadDoneSymbol] = true; - setStatusOrRemoveBadges.call(this, "loading"); - - new Processing(200, () => { - this.fetch() - .then(() => { - checkOptionState.call(this); - requestAnimationFrame(() => { - show.call(this); - }) - }) - .catch((e) => { - - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - setStatusOrRemoveBadges.call(this, "error"); - }); - }) - .run() - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - setStatusOrRemoveBadges.call(this, "error"); - }); - - return; - } - - const options = getOptionElements.call(this); - if (options.length === 0) { - return; - } - - this[popperElementSymbol].style.visibility = "hidden"; - this[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK; - setStatusOrRemoveBadges.call(this, "open"); - - addAttributeToken(this[controlElementSymbol], "class", "open"); - - new Processing(() => { - calcAndSetOptionsDimension.call(this); - focusFilter.call(this); - this[popperElementSymbol].style.removeProperty("visibility"); - updatePopper.call(this); - }) - .run() - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - }); + if (this.getOption("disabled", undefined) === true) { + return; + } + + if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) { + return; + } + + focusFilter.call(this); + + const lazyLoadFlag = + this.getOption("features.lazyLoad") && this[lazyLoadDoneSymbol] !== true; + + if (lazyLoadFlag === true) { + this[lazyLoadDoneSymbol] = true; + setStatusOrRemoveBadges.call(this, "loading"); + + new Processing(200, () => { + this.fetch() + .then(() => { + checkOptionState.call(this); + requestAnimationFrame(() => { + show.call(this); + }); + }) + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + setStatusOrRemoveBadges.call(this, "error"); + }); + }) + .run() + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + setStatusOrRemoveBadges.call(this, "error"); + }); + + return; + } + + const options = getOptionElements.call(this); + if (options.length === 0) { + return; + } + + this[popperElementSymbol].style.visibility = "hidden"; + this[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK; + setStatusOrRemoveBadges.call(this, "open"); + + addAttributeToken(this[controlElementSymbol], "class", "open"); + + new Processing(() => { + calcAndSetOptionsDimension.call(this); + focusFilter.call(this); + this[popperElementSymbol].style.removeProperty("visibility"); + updatePopper.call(this); + }) + .run() + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + }); } /** * @private */ function toggle() { - if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) { - hide.call(this); - } else { - show.call(this); - } + if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) { + hide.call(this); + } else { + show.call(this); + } } /** @@ -2225,188 +2215,188 @@ function toggle() { * @fires monster-selection-cleared */ function initEventHandler() { - const self = this; - - /** - * @param {Event} event - */ - self[clearOptionEventHandler] = (event) => { - const element = findTargetElementFromEvent( - event, - ATTRIBUTE_ROLE, - "remove-badge", - ); - - if (element instanceof HTMLElement) { - const badge = findClosestByAttribute(element, ATTRIBUTE_ROLE, "badge"); - if (badge instanceof HTMLElement) { - const value = badge.getAttribute(`${ATTRIBUTE_PREFIX}value`); - - let selection = self.getOption("selection"); - selection = selection.filter((b) => { - return value !== b.value; - }); - - setSelection - .call(self, selection) - .then(() => { - fireCustomEvent(self, "monster-selection-removed", { - value, - }); - }) - .catch((e) => { - addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.message); - }); - } - } - }; - - /** - * @param {Event} event - */ - self[closeEventHandler] = (event) => { - const path = event.composedPath(); - - for (const [, element] of Object.entries(path)) { - if (element === self) { - return; - } - } - hide.call(self); - }; - - /** - * @param {Event} event - */ - self[inputEventHandler] = (event) => { - const path = event.composedPath(); - const element = path?.[0]; - - if (element instanceof HTMLElement) { - if ( - element.hasAttribute(ATTRIBUTE_ROLE) && - element.getAttribute(ATTRIBUTE_ROLE) === "option-control" - ) { - fireCustomEvent(self, "monster-change", { - type: event.type, - value: element.value, - checked: element.checked, - }); - } else if ( - element.hasAttribute(ATTRIBUTE_ROLE) && - element.getAttribute(ATTRIBUTE_ROLE) === "filter" - ) { - } - } - }; - - /** - * @param {Event} event - */ - self[changeEventHandler] = (event) => { - gatherState.call(self); - fireCustomEvent(self, "monster-changed", event?.detail); - }; - - self[keyEventHandler] = (event) => { - const path = event.composedPath(); - const element = path.shift(); - - let role; - - if (element instanceof HTMLElement) { - if (element.hasAttribute(ATTRIBUTE_ROLE)) { - role = element.getAttribute(ATTRIBUTE_ROLE); - } else if (element === this) { - show.call(this); - // focusFilter.call(self); - } else { - const e = element.closest(`[${ATTRIBUTE_ROLE}]`); - if (e instanceof HTMLElement && e.hasAttribute(ATTRIBUTE_ROLE)) { - role = e.getAttribute(ATTRIBUTE_ROLE); - } - } - } else { - return; - } - - switch (role) { - case "filter": - handleFilterKeyboardEvents.call(self, event); - break; - case "option-label": - case "option-control": - case "option": - handleOptionKeyboardEvents.call(self, event); - break; - case "control": - case "toggle": - handleToggleKeyboardEvents.call(self, event); - break; - } - }; - - const types = self.getOption("toggleEventType", ["click"]); - - for (const [, type] of Object.entries(types)) { - self[controlElementSymbol] - .querySelector(`[${ATTRIBUTE_ROLE}="container"]`) - .addEventListener(type, function (event) { - const element = findTargetElementFromEvent( - event, - ATTRIBUTE_ROLE, - "remove-badge", - ); - if (element instanceof HTMLElement) { - return; - } - - toggle.call(self); - }); - - self[controlElementSymbol] - .querySelector(`[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`) - .addEventListener(type, function (event) { - if (self.getOption("disabled", undefined) === true) { - return; - } - - const path = event.composedPath(); - const element = path?.[0]; - if (element instanceof HTMLElement) { - const control = element.closest( - `[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`, - ); - if (control instanceof HTMLElement) { - if (control.classList.contains("clear")) { - clearSelection.call(self); - - fireCustomEvent(self, "monster-selection-cleared", {}); - } else { - const element = findTargetElementFromEvent( - event, - ATTRIBUTE_ROLE, - "remove-badge", - ); - if (element instanceof HTMLElement) { - return; - } - - toggle.call(self); - } - } - } - }); - - // badge, selection - self.addEventListener(type, self[clearOptionEventHandler]); - } - - self.addEventListener("monster-change", self[changeEventHandler]); - self.addEventListener("input", self[inputEventHandler]); - self.addEventListener("keydown", self[keyEventHandler]); - - return self; + const self = this; + + /** + * @param {Event} event + */ + self[clearOptionEventHandler] = (event) => { + const element = findTargetElementFromEvent( + event, + ATTRIBUTE_ROLE, + "remove-badge", + ); + + if (element instanceof HTMLElement) { + const badge = findClosestByAttribute(element, ATTRIBUTE_ROLE, "badge"); + if (badge instanceof HTMLElement) { + const value = badge.getAttribute(`${ATTRIBUTE_PREFIX}value`); + + let selection = self.getOption("selection"); + selection = selection.filter((b) => { + return value !== b.value; + }); + + setSelection + .call(self, selection) + .then(() => { + fireCustomEvent(self, "monster-selection-removed", { + value, + }); + }) + .catch((e) => { + addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, e.message); + }); + } + } + }; + + /** + * @param {Event} event + */ + self[closeEventHandler] = (event) => { + const path = event.composedPath(); + + for (const [, element] of Object.entries(path)) { + if (element === self) { + return; + } + } + hide.call(self); + }; + + /** + * @param {Event} event + */ + self[inputEventHandler] = (event) => { + const path = event.composedPath(); + const element = path?.[0]; + + if (element instanceof HTMLElement) { + if ( + element.hasAttribute(ATTRIBUTE_ROLE) && + element.getAttribute(ATTRIBUTE_ROLE) === "option-control" + ) { + fireCustomEvent(self, "monster-change", { + type: event.type, + value: element.value, + checked: element.checked, + }); + } else if ( + element.hasAttribute(ATTRIBUTE_ROLE) && + element.getAttribute(ATTRIBUTE_ROLE) === "filter" + ) { + } + } + }; + + /** + * @param {Event} event + */ + self[changeEventHandler] = (event) => { + gatherState.call(self); + fireCustomEvent(self, "monster-changed", event?.detail); + }; + + self[keyEventHandler] = (event) => { + const path = event.composedPath(); + const element = path.shift(); + + let role; + + if (element instanceof HTMLElement) { + if (element.hasAttribute(ATTRIBUTE_ROLE)) { + role = element.getAttribute(ATTRIBUTE_ROLE); + } else if (element === this) { + show.call(this); + // focusFilter.call(self); + } else { + const e = element.closest(`[${ATTRIBUTE_ROLE}]`); + if (e instanceof HTMLElement && e.hasAttribute(ATTRIBUTE_ROLE)) { + role = e.getAttribute(ATTRIBUTE_ROLE); + } + } + } else { + return; + } + + switch (role) { + case "filter": + handleFilterKeyboardEvents.call(self, event); + break; + case "option-label": + case "option-control": + case "option": + handleOptionKeyboardEvents.call(self, event); + break; + case "control": + case "toggle": + handleToggleKeyboardEvents.call(self, event); + break; + } + }; + + const types = self.getOption("toggleEventType", ["click"]); + + for (const [, type] of Object.entries(types)) { + self[controlElementSymbol] + .querySelector(`[${ATTRIBUTE_ROLE}="container"]`) + .addEventListener(type, function (event) { + const element = findTargetElementFromEvent( + event, + ATTRIBUTE_ROLE, + "remove-badge", + ); + if (element instanceof HTMLElement) { + return; + } + + toggle.call(self); + }); + + self[controlElementSymbol] + .querySelector(`[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`) + .addEventListener(type, function (event) { + if (self.getOption("disabled", undefined) === true) { + return; + } + + const path = event.composedPath(); + const element = path?.[0]; + if (element instanceof HTMLElement) { + const control = element.closest( + `[${ATTRIBUTE_ROLE}="status-or-remove-badges"]`, + ); + if (control instanceof HTMLElement) { + if (control.classList.contains("clear")) { + clearSelection.call(self); + + fireCustomEvent(self, "monster-selection-cleared", {}); + } else { + const element = findTargetElementFromEvent( + event, + ATTRIBUTE_ROLE, + "remove-badge", + ); + if (element instanceof HTMLElement) { + return; + } + + toggle.call(self); + } + } + } + }); + + // badge, selection + self.addEventListener(type, self[clearOptionEventHandler]); + } + + self.addEventListener("monster-change", self[changeEventHandler]); + self.addEventListener("input", self[inputEventHandler]); + self.addEventListener("keydown", self[keyEventHandler]); + + return self; } /** @@ -2414,72 +2404,70 @@ function initEventHandler() { * @return {Select} */ function setStatusOrRemoveBadges(suggestion) { - - requestAnimationFrame(() => { - const selection = this.getOption("selection"); - - const clearAllFlag = - isArray(selection) && - selection.length > 0 && - this.getOption("features.clearAll") === true; - - const current = this.getOption("classes.statusOrRemoveBadge"); - - if (suggestion === "error") { - if (current !== "error") { - this.setOption("classes.statusOrRemoveBadge", "error"); - } - return; - } - - if (this[isLoadingSymbol] === true) { - if (current !== "loading") { - this.setOption("classes.statusOrRemoveBadge", "loading"); - } - return; - } - - if (suggestion === "loading") { - if (current !== "loading") { - this.setOption("classes.statusOrRemoveBadge", "loading"); - } - return; - } - - if (clearAllFlag) { - if (current !== "clear") { - this.setOption("classes.statusOrRemoveBadge", "clear"); - } - return; - } - - if (this[controlElementSymbol].classList.contains("open")) { - if (current !== "open") { - this.setOption("classes.statusOrRemoveBadge", "open"); - } - return; - } - - const options = this.getOption("options"); - if ( - options === undefined || - options === null || - (isArray(options) && options.length === 0) - ) { - if (current !== "empty") { - this.setOption("classes.statusOrRemoveBadge", "empty"); - } - return; - } - - if (suggestion) { - if (current !== suggestion) { - this.setOption("classes.statusOrRemoveBadge", suggestion); - } - return; - } - }) - + requestAnimationFrame(() => { + const selection = this.getOption("selection"); + + const clearAllFlag = + isArray(selection) && + selection.length > 0 && + this.getOption("features.clearAll") === true; + + const current = this.getOption("classes.statusOrRemoveBadge"); + + if (suggestion === "error") { + if (current !== "error") { + this.setOption("classes.statusOrRemoveBadge", "error"); + } + return; + } + + if (this[isLoadingSymbol] === true) { + if (current !== "loading") { + this.setOption("classes.statusOrRemoveBadge", "loading"); + } + return; + } + + if (suggestion === "loading") { + if (current !== "loading") { + this.setOption("classes.statusOrRemoveBadge", "loading"); + } + return; + } + + if (clearAllFlag) { + if (current !== "clear") { + this.setOption("classes.statusOrRemoveBadge", "clear"); + } + return; + } + + if (this[controlElementSymbol].classList.contains("open")) { + if (current !== "open") { + this.setOption("classes.statusOrRemoveBadge", "open"); + } + return; + } + + const options = this.getOption("options"); + if ( + options === undefined || + options === null || + (isArray(options) && options.length === 0) + ) { + if (current !== "empty") { + this.setOption("classes.statusOrRemoveBadge", "empty"); + } + return; + } + + if (suggestion) { + if (current !== suggestion) { + this.setOption("classes.statusOrRemoveBadge", suggestion); + } + return; + } + }); } /** @@ -2488,68 +2476,68 @@ function setStatusOrRemoveBadges(suggestion) { * @throws {Error} no shadow-root is defined */ function initControlReferences() { - if (!this.shadowRoot) { - throw new Error("no shadow-root is defined"); - } - - this[controlElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}=control]`, - ); - this[selectionElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}=selection]`, - ); - this[containerElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}=container]`, - ); - this[popperElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}=popper]`, - ); - this[inlineFilterElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}=filter][name="inline-filter"]`, - ); - this[popperFilterElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}=filter][name="popper-filter"]`, - ); - this[popperFilterContainerElementSymbol] = - this[popperFilterElementSymbol].parentElement; - this[optionsElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}=options]`, - ); - this[noOptionsAvailableElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}="no-options"]`, - ); - this[statusOrRemoveBadgesElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}=status-or-remove-badges]`, - ); + if (!this.shadowRoot) { + throw new Error("no shadow-root is defined"); + } + + this[controlElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}=control]`, + ); + this[selectionElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}=selection]`, + ); + this[containerElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}=container]`, + ); + this[popperElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}=popper]`, + ); + this[inlineFilterElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}=filter][name="inline-filter"]`, + ); + this[popperFilterElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}=filter][name="popper-filter"]`, + ); + this[popperFilterContainerElementSymbol] = + this[popperFilterElementSymbol].parentElement; + this[optionsElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}=options]`, + ); + this[noOptionsAvailableElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}="no-options"]`, + ); + this[statusOrRemoveBadgesElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}=status-or-remove-badges]`, + ); } /** * @private */ function updatePopper() { - if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) { - return; - } - - if (this.getOption("disabled", false) === true) { - return; - } - - new Processing(() => { - calcAndSetOptionsDimension.call(this); - positionPopper.call( - this, - this[controlElementSymbol], - this[popperElementSymbol], - this.getOption("popper", {}), - ); - }) - .run() - .catch((e) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); - }); - - return this; + if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) { + return; + } + + if (this.getOption("disabled", false) === true) { + return; + } + + new Processing(() => { + calcAndSetOptionsDimension.call(this); + positionPopper.call( + this, + this[controlElementSymbol], + this[popperElementSymbol], + this.getOption("popper", {}), + ); + }) + .run() + .catch((e) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); + }); + + return this; } /** @@ -2557,8 +2545,8 @@ function updatePopper() { * @return {string} */ function getTemplate() { - // language=HTML - return ` + // language=HTML + return ` <template id="options"> <div data-monster-role="option" tabindex="-1" data-monster-attributes=" diff --git a/source/components/form/stylesheet/field-set.mjs b/source/components/form/stylesheet/field-set.mjs index 700c79addad4f159d553607700dcd08ee9e98ea3..1d70cf498dfd6300402d0371081e0c8babc0066a 100644 --- a/source/components/form/stylesheet/field-set.mjs +++ b/source/components/form/stylesheet/field-set.mjs @@ -10,10 +10,10 @@ * For more information about purchasing a commercial license, please contact schukai GmbH. */ -import {addAttributeToken} from "../../../dom/attributes.mjs"; -import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs"; +import { addAttributeToken } from "../../../dom/attributes.mjs"; +import { ATTRIBUTE_ERRORMESSAGE } from "../../../dom/constants.mjs"; -export {FieldSetStyleSheet} +export { FieldSetStyleSheet }; /** * @private @@ -22,10 +22,17 @@ export {FieldSetStyleSheet} const FieldSetStyleSheet = new CSSStyleSheet(); try { - FieldSetStyleSheet.insertRule(` + FieldSetStyleSheet.insertRule( + ` @layer fieldset { :after,:before,:root{--monster-color-gray-1:#f6f6f6;--monster-color-gray-2:#e2e2e2;--monster-color-gray-3:#8b8b8b;--monster-color-gray-4:#6f6f6f;--monster-color-gray-5:#3e3e3e;--monster-color-gray-6:#222;--monster-color-rose-1:#fff7f9;--monster-color-rose-2:#ffdce5;--monster-color-rose-3:#ff3b8d;--monster-color-rose-4:#db0072;--monster-color-rose-5:#800040;--monster-color-rose-6:#4c0023;--monster-color-raspberry-1:#fff8f8;--monster-color-raspberry-2:#ffdddf;--monster-color-raspberry-3:#ff426c;--monster-color-raspberry-4:#de0051;--monster-color-raspberry-5:#82002c;--monster-color-raspberry-6:#510018;--monster-color-red-1:#fff8f6;--monster-color-red-2:#ffddd8;--monster-color-red-3:#ff4647;--monster-color-red-4:#e0002b;--monster-color-red-5:#830014;--monster-color-red-6:#530003;--monster-color-orange-1:#fff8f5;--monster-color-orange-2:#ffded1;--monster-color-orange-3:#fd4d00;--monster-color-orange-4:#cd3c00;--monster-color-orange-5:#752100;--monster-color-orange-6:#401600;--monster-color-cinnamon-1:#fff8f3;--monster-color-cinnamon-2:#ffdfc6;--monster-color-cinnamon-3:#d57300;--monster-color-cinnamon-4:#ac5c00;--monster-color-cinnamon-5:#633300;--monster-color-cinnamon-6:#371d00;--monster-color-amber-1:#fff8ef;--monster-color-amber-2:#ffe0b2;--monster-color-amber-3:#b98300;--monster-color-amber-4:#926700;--monster-color-amber-5:#523800;--monster-color-amber-6:#302100;--monster-color-yellow-1:#fff9e5;--monster-color-yellow-2:#ffe53e;--monster-color-yellow-3:#9c8b00;--monster-color-yellow-4:#7d6f00;--monster-color-yellow-5:#463d00;--monster-color-yellow-6:#292300;--monster-color-lime-1:#f7ffac;--monster-color-lime-2:#d5f200;--monster-color-lime-3:#819300;--monster-color-lime-4:#677600;--monster-color-lime-5:#394100;--monster-color-lime-6:#222600;--monster-color-chartreuse-1:#e5ffc3;--monster-color-chartreuse-2:#98fb00;--monster-color-chartreuse-3:#5c9b00;--monster-color-chartreuse-4:#497c00;--monster-color-chartreuse-5:#264500;--monster-color-chartreuse-6:#182600;--monster-color-green-1:#e0ffd9;--monster-color-green-2:#72ff6c;--monster-color-green-3:#00a21f;--monster-color-green-4:#008217;--monster-color-green-5:#004908;--monster-color-green-6:#062800;--monster-color-emerald-1:#dcffe6;--monster-color-emerald-2:#5dffa2;--monster-color-emerald-3:#00a05a;--monster-color-emerald-4:#008147;--monster-color-emerald-5:#004825;--monster-color-emerald-6:#002812;--monster-color-aquamarine-1:#daffef;--monster-color-aquamarine-2:#42ffc6;--monster-color-aquamarine-3:#009f78;--monster-color-aquamarine-4:#007f5f;--monster-color-aquamarine-5:#004734;--monster-color-aquamarine-6:#00281b;--monster-color-teal-1:#d7fff7;--monster-color-teal-2:#00ffe4;--monster-color-teal-3:#009e8c;--monster-color-teal-4:#007c6e;--monster-color-teal-5:#00443c;--monster-color-teal-6:#002722;--monster-color-cyan-1:#c4fffe;--monster-color-cyan-2:#00fafb;--monster-color-cyan-3:#00999a;--monster-color-cyan-4:#007a7b;--monster-color-cyan-5:#004344;--monster-color-cyan-6:#002525;--monster-color-powder-1:#dafaff;--monster-color-powder-2:#8df0ff;--monster-color-powder-3:#0098a9;--monster-color-powder-4:#007987;--monster-color-powder-5:#004048;--monster-color-powder-6:#002227;--monster-color-sky-1:#e3f7ff;--monster-color-sky-2:#aee9ff;--monster-color-sky-3:#0094b4;--monster-color-sky-4:#007590;--monster-color-sky-5:#00404f;--monster-color-sky-6:#001f28;--monster-color-cerulean-1:#e8f6ff;--monster-color-cerulean-2:#b9e3ff;--monster-color-cerulean-3:#0092c5;--monster-color-cerulean-4:#00749d;--monster-color-cerulean-5:#003c54;--monster-color-cerulean-6:#001d2a;--monster-color-azure-1:#e8f2ff;--monster-color-azure-2:#c6e0ff;--monster-color-azure-3:#008fdb;--monster-color-azure-4:#0071af;--monster-color-azure-5:#003b5e;--monster-color-azure-6:#001c30;--monster-color-blue-1:#f0f4ff;--monster-color-blue-2:#d4e0ff;--monster-color-blue-3:#0089fc;--monster-color-blue-4:#006dca;--monster-color-blue-5:#00386d;--monster-color-blue-6:#001a39;--monster-color-indigo-1:#f3f3ff;--monster-color-indigo-2:#deddff;--monster-color-indigo-3:#657eff;--monster-color-indigo-4:#0061fc;--monster-color-indigo-5:#00328a;--monster-color-indigo-6:#001649;--monster-color-violet-1:#f7f1ff;--monster-color-violet-2:#e8daff;--monster-color-violet-3:#9b70ff;--monster-color-violet-4:#794aff;--monster-color-violet-5:#2d0fbf;--monster-color-violet-6:#0b0074;--monster-color-purple-1:#fdf4ff;--monster-color-purple-2:#f7d9ff;--monster-color-purple-3:#d150ff;--monster-color-purple-4:#b01fe3;--monster-color-purple-5:#660087;--monster-color-purple-6:#3a004f;--monster-color-magenta-1:#fff3fc;--monster-color-magenta-2:#ffd7f6;--monster-color-magenta-3:#f911e0;--monster-color-magenta-4:#ca00b6;--monster-color-magenta-5:#740068;--monster-color-magenta-6:#44003c;--monster-color-pink-1:#fff7fb;--monster-color-pink-2:#ffdcec;--monster-color-pink-3:#ff2fb2;--monster-color-pink-4:#d2008f;--monster-color-pink-5:#790051;--monster-color-pink-6:#4b0030;--monster-gradient-tangerine-1:#e5b875;--monster-gradient-tangerine-2:#d9a362;--monster-gradient-tangerine-3:#c08a4e;--monster-gradient-tangerine-4:#a7713b;--monster-gradient-tangerine-5:#8f5a28;--monster-gradient-tangerine-6:#360505;--monster-color-seashell-1:#f7f5ef;--monster-color-seashell-2:#e5e2d9;--monster-color-seashell-3:#cbc6b3;--monster-color-seashell-4:#a19d8a;--monster-color-seashell-5:#7a7566;--monster-color-seashell-6:#514d3f}.monster-theme-primary-1{background-color:var(--monster-bg-color-primary-1);color:var(--monster-color-primary-1)}.monster-theme-primary-disabled-1{background-color:var(--monster-bg-color-primary-disabled-1);color:var(--monster-color-primary-disabled-1)}.monster-theme-secondary-1{background-color:var(--monster-bg-color-secondary-1);color:var(--monster-color-secondary-1)}.monster-theme-tertiary-1{background-color:var(--monster-bg-color-tertiary-1);color:var(--monster-color-tertiary-1)}.monster-theme-destructive-1{background-color:var(--monster-bg-color-destructive-1);color:var(--monster-color-destructive-1)}.monster-theme-success-1{background-color:var(--monster-bg-color-success-1);color:var(--monster-color-success-1)}.monster-theme-warning-1{background-color:var(--monster-bg-color-warning-1);color:var(--monster-color-warning-1)}.monster-theme-error-1{background-color:var(--monster-bg-color-error-1);color:var(--monster-color-error-1)}.monster-theme-selection-1{background-color:var(--monster-bg-color-selection-1);color:var(--monster-color-selection-1)}.monster-border-color-1{border-color:var(--monster-color-border-1)}.monster-color-neutral-1{color:var(--monster-color-primary-1)}.monster-bg-color-primary-1{background-color:var(--monster-bg-color-primary-1)}.monster-bg-color-secondary-1{background-color:var(--monster-bg-color-secondary-1)}.monster-bg-color-tertiary-1{background-color:var(--monster-bg-color-tertiary-1)}.monster-color-primary-1{background-color:var(--monster-bg-color-primary-1);color:var(--monster-color-primary-1)}.monster-color-secondary-1{background-color:var(--monster-bg-color-secondary-1);color:var(--monster-color-secondary-1)}.monster-color-tertiary-1{background-color:var(--monster-bg-color-tertiary-1);color:var(--monster-color-tertiary-1)}.monster-color-destructive-1{background-color:var(--monster-bg-color-destructive-1);color:var(--monster-color-destructive-1)}.monster-color-success-1{background-color:var(--monster-bg-color-success-1);color:var(--monster-color-success-1)}.monster-color-warning-1{background-color:var(--monster-bg-color-warning-1);color:var(--monster-color-warning-1)}.monster-color-error-1{background-color:var(--monster-bg-color-error-1);color:var(--monster-color-error-1)}.monster-color-selection-1{background-color:var(--monster-bg-color-selection-1);color:var(--monster-color-selection-1)}.monster-theme-primary-2{background-color:var(--monster-bg-color-primary-2);color:var(--monster-color-primary-2)}.monster-theme-primary-disabled-2{background-color:var(--monster-bg-color-primary-disabled-2);color:var(--monster-color-primary-disabled-2)}.monster-theme-secondary-2{background-color:var(--monster-bg-color-secondary-2);color:var(--monster-color-secondary-2)}.monster-theme-tertiary-2{background-color:var(--monster-bg-color-tertiary-2);color:var(--monster-color-tertiary-2)}.monster-theme-destructive-2{background-color:var(--monster-bg-color-destructive-2);color:var(--monster-color-destructive-2)}.monster-theme-success-2{background-color:var(--monster-bg-color-success-2);color:var(--monster-color-success-2)}.monster-theme-warning-2{background-color:var(--monster-bg-color-warning-2);color:var(--monster-color-warning-2)}.monster-theme-error-2{background-color:var(--monster-bg-color-error-2);color:var(--monster-color-error-2)}.monster-theme-selection-2{background-color:var(--monster-bg-color-selection-2);color:var(--monster-color-selection-2)}.monster-border-color-2{border-color:var(--monster-color-border-2)}.monster-color-neutral-2{color:var(--monster-color-primary-2)}.monster-bg-color-primary-2{background-color:var(--monster-bg-color-primary-2)}.monster-bg-color-secondary-2{background-color:var(--monster-bg-color-secondary-2)}.monster-bg-color-tertiary-2{background-color:var(--monster-bg-color-tertiary-2)}.monster-color-primary-2{background-color:var(--monster-bg-color-primary-2);color:var(--monster-color-primary-2)}.monster-color-secondary-2{background-color:var(--monster-bg-color-secondary-2);color:var(--monster-color-secondary-2)}.monster-color-tertiary-2{background-color:var(--monster-bg-color-tertiary-2);color:var(--monster-color-tertiary-2)}.monster-color-destructive-2{background-color:var(--monster-bg-color-destructive-2);color:var(--monster-color-destructive-2)}.monster-color-success-2{background-color:var(--monster-bg-color-success-2);color:var(--monster-color-success-2)}.monster-color-warning-2{background-color:var(--monster-bg-color-warning-2);color:var(--monster-color-warning-2)}.monster-color-error-2{background-color:var(--monster-bg-color-error-2);color:var(--monster-color-error-2)}.monster-color-selection-2{background-color:var(--monster-bg-color-selection-2);color:var(--monster-color-selection-2)}.monster-theme-primary-3{background-color:var(--monster-bg-color-primary-3);color:var(--monster-color-primary-3)}.monster-theme-primary-disabled-3{background-color:var(--monster-bg-color-primary-disabled-3);color:var(--monster-color-primary-disabled-3)}.monster-theme-secondary-3{background-color:var(--monster-bg-color-secondary-3);color:var(--monster-color-secondary-3)}.monster-theme-tertiary-3{background-color:var(--monster-bg-color-tertiary-3);color:var(--monster-color-tertiary-3)}.monster-theme-destructive-3{background-color:var(--monster-bg-color-destructive-3);color:var(--monster-color-destructive-3)}.monster-theme-success-3{background-color:var(--monster-bg-color-success-3);color:var(--monster-color-success-3)}.monster-theme-warning-3{background-color:var(--monster-bg-color-warning-3);color:var(--monster-color-warning-3)}.monster-theme-error-3{background-color:var(--monster-bg-color-error-3);color:var(--monster-color-error-3)}.monster-theme-selection-3{background-color:var(--monster-bg-color-selection-3);color:var(--monster-color-selection-3)}.monster-border-color-3{border-color:var(--monster-color-border-3)}.monster-color-neutral-3{color:var(--monster-color-primary-3)}.monster-bg-color-primary-3{background-color:var(--monster-bg-color-primary-3)}.monster-bg-color-secondary-3{background-color:var(--monster-bg-color-secondary-3)}.monster-bg-color-tertiary-3{background-color:var(--monster-bg-color-tertiary-3)}.monster-color-primary-3{background-color:var(--monster-bg-color-primary-3);color:var(--monster-color-primary-3)}.monster-color-secondary-3{background-color:var(--monster-bg-color-secondary-3);color:var(--monster-color-secondary-3)}.monster-color-tertiary-3{background-color:var(--monster-bg-color-tertiary-3);color:var(--monster-color-tertiary-3)}.monster-color-destructive-3{background-color:var(--monster-bg-color-destructive-3);color:var(--monster-color-destructive-3)}.monster-color-success-3{background-color:var(--monster-bg-color-success-3);color:var(--monster-color-success-3)}.monster-color-warning-3{background-color:var(--monster-bg-color-warning-3);color:var(--monster-color-warning-3)}.monster-color-error-3{background-color:var(--monster-bg-color-error-3);color:var(--monster-color-error-3)}.monster-color-selection-3{background-color:var(--monster-bg-color-selection-3);color:var(--monster-color-selection-3)}.monster-theme-primary-4{background-color:var(--monster-bg-color-primary-4);color:var(--monster-color-primary-4)}.monster-theme-primary-disabled-4{background-color:var(--monster-bg-color-primary-disabled-4);color:var(--monster-color-primary-disabled-4)}.monster-theme-secondary-4{background-color:var(--monster-bg-color-secondary-4);color:var(--monster-color-secondary-4)}.monster-theme-tertiary-4{background-color:var(--monster-bg-color-tertiary-4);color:var(--monster-color-tertiary-4)}.monster-theme-destructive-4{background-color:var(--monster-bg-color-destructive-4);color:var(--monster-color-destructive-4)}.monster-theme-success-4{background-color:var(--monster-bg-color-success-4);color:var(--monster-color-success-4)}.monster-theme-warning-4{background-color:var(--monster-bg-color-warning-4);color:var(--monster-color-warning-4)}.monster-theme-error-4{background-color:var(--monster-bg-color-error-4);color:var(--monster-color-error-4)}.monster-theme-selection-4{background-color:var(--monster-bg-color-selection-4);color:var(--monster-color-selection-4)}.monster-border-color-4{border-color:var(--monster-color-border-4)}.monster-color-neutral-4{color:var(--monster-color-primary-4)}.monster-bg-color-primary-4{background-color:var(--monster-bg-color-primary-4)}.monster-bg-color-secondary-4{background-color:var(--monster-bg-color-secondary-4)}.monster-bg-color-tertiary-4{background-color:var(--monster-bg-color-tertiary-4)}.monster-color-primary-4{background-color:var(--monster-bg-color-primary-4);color:var(--monster-color-primary-4)}.monster-color-secondary-4{background-color:var(--monster-bg-color-secondary-4);color:var(--monster-color-secondary-4)}.monster-color-tertiary-4{background-color:var(--monster-bg-color-tertiary-4);color:var(--monster-color-tertiary-4)}.monster-color-destructive-4{background-color:var(--monster-bg-color-destructive-4);color:var(--monster-color-destructive-4)}.monster-color-success-4{background-color:var(--monster-bg-color-success-4);color:var(--monster-color-success-4)}.monster-color-warning-4{background-color:var(--monster-bg-color-warning-4);color:var(--monster-color-warning-4)}.monster-color-error-4{background-color:var(--monster-bg-color-error-4);color:var(--monster-color-error-4)}.monster-color-selection-4{background-color:var(--monster-bg-color-selection-4);color:var(--monster-color-selection-4)}.monster-theme-control-container-1,.monster-theme-control-row-1{border:1px solid var(--monster-theme-control-border-color)}.monster-theme-control-container-1,.monster-theme-control-element,.monster-theme-control-row-1{background-color:var(--monster-theme-control-bg-color);color:var(--monster-theme-control-color)}.monster-theme-control-background{background-color:var(--monster-theme-control-bg-color)}.monster-theme-background-inherit{background-color:inherit!important}.monster-theme-on{background-color:var(--monster-theme-on-bg-color);color:var(--monster-theme-on-color)}.monster-theme-off{background-color:var(--monster-theme-off-bg-color);color:var(--monster-theme-off-color)}.monster-border-primary-1,.monster-border-primary-2,.monster-border-primary-3,.monster-border-primary-4{border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width)}.monster-border-0{border-radius:0;border-style:none;border-width:0}.monster-border-primary-1{border-color:var(--monster-bg-color-primary-1)}.monster-border-primary-2{border-color:var(--monster-bg-color-primary-2)}.monster-border-primary-3{border-color:var(--monster-bg-color-primary-3)}.monster-border-primary-4{border-color:var(--monster-bg-color-primary-4)}.monster-border-secondary-1,.monster-border-secondary-2,.monster-border-secondary-3,.monster-border-secondary-4{border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width)}.monster-border-secondary-1{border-color:var(--monster-bg-color-secondary-1)}.monster-border-secondary-2{border-color:var(--monster-bg-color-secondary-2)}.monster-border-secondary-3{border-color:var(--monster-bg-color-secondary-3)}.monster-border-secondary-4{border-color:var(--monster-bg-color-secondary-4)}.monster-border-tertiary-1,.monster-border-tertiary-2,.monster-border-tertiary-3,.monster-border-tertiary-4{border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width)}.monster-border-tertiary-1{border-color:var(--monster-bg-color-tertiary-1)}.monster-border-tertiary-2{border-color:var(--monster-bg-color-tertiary-2)}.monster-border-tertiary-3{border-color:var(--monster-bg-color-tertiary-3)}.monster-border-tertiary-4{border-color:var(--monster-bg-color-tertiary-4)}input,meter,progress,select,textarea{accent-color:var(--monster-color-secondary-2);background-color:var(--monster-bg-color-primary-1);border-color:var(--monster-theme-control-border-color);border-radius:var(--monster-theme-control-border-radius);border-style:var(--monster-theme-control-border-style);border-width:var(--monster-theme-control-border-width);box-sizing:border-box;color:var(--monster-color-primary-1);font-family:inherit;font-size:100%;margin:0;outline:none}input,select,textarea{height:-moz-fit-content;height:fit-content;padding:.4rem .6rem}textarea{min-height:6rem;resize:vertical}input[type=color]{height:2rem;margin:0;padding:.1rem;width:2rem}input:hover:not([type=radio]):not([type=checkbox]):not([type=range]),select:hover,textarea:hover{box-shadow:var(--monster-box-shadow-2);transition:background .8s,color .25s .0833333333s}input:focus,select:focus,textarea:focus{outline:1px dashed var(--monster-color-selection-3);outline-offset:3px}[data-monster-role=control]{box-sizing:border-box;outline:none;width:100%}[data-monster-role=control].flex{align-items:center;display:flex;flex-direction:row}:host{box-sizing:border-box;display:block}.monster-badge-primary{padding:.25em .4em}.monster-badge-primary,.monster-badge-primary-pill{background-color:var(--monster-bg-color-primary-4);border-radius:.25rem;color:var(--monster-color-primary-4);display:inline-block;font-size:75%;font-weight:700;line-height:1;text-align:center;text-decoration:none;vertical-align:baseline;white-space:nowrap}.monster-badge-primary-pill{border-radius:10rem;padding:.25em .6em}.monster-badge-secondary{padding:.25em .4em}.monster-badge-secondary,.monster-badge-secondary-pill{background-color:var(--monster-bg-color-secondary-3);border-radius:.25rem;color:var(--monster-color-secondary-3);display:inline-block;font-size:75%;font-weight:700;line-height:1;text-align:center;text-decoration:none;vertical-align:baseline;white-space:nowrap}.monster-badge-secondary-pill{border-radius:10rem;padding:.25em .6em}.monster-badge-tertiary{padding:.25em .4em}.monster-badge-tertiary,.monster-badge-tertiary-pill{background-color:var(--monster-bg-color-tertiary-3);border-radius:.25rem;color:var(--monster-color-tertiary-3);display:inline-block;font-size:75%;font-weight:700;line-height:1;text-align:center;text-decoration:none;vertical-align:baseline;white-space:nowrap}.monster-badge-tertiary-pill{border-radius:10rem;padding:.25em .6em}.monster-badge-destructive{padding:.25em .4em}.monster-badge-destructive,.monster-badge-destructive-pill{background-color:var(--monster-bg-color-destructive-1);border-radius:.25rem;color:var(--monster-color-destructive-1);display:inline-block;font-size:75%;font-weight:700;line-height:1;text-align:center;text-decoration:none;vertical-align:baseline;white-space:nowrap}.monster-badge-destructive-pill{border-radius:10rem;padding:.25em .6em}.monster-badge-success{padding:.25em .4em}.monster-badge-success,.monster-badge-success-pill{background-color:var(--monster-bg-color-success-1);border-radius:.25rem;color:var(--monster-color-success-1);display:inline-block;font-size:75%;font-weight:700;line-height:1;text-align:center;text-decoration:none;vertical-align:baseline;white-space:nowrap}.monster-badge-success-pill{border-radius:10rem;padding:.25em .6em}.monster-badge-warning{padding:.25em .4em}.monster-badge-warning,.monster-badge-warning-pill{background-color:var(--monster-bg-color-warning-1);border-radius:.25rem;color:var(--monster-color-warning-1);display:inline-block;font-size:75%;font-weight:700;line-height:1;text-align:center;text-decoration:none;vertical-align:baseline;white-space:nowrap}.monster-badge-warning-pill{border-radius:10rem;padding:.25em .6em}.monster-badge-error{padding:.25em .4em}.monster-badge-error,.monster-badge-error-pill{background-color:var(--monster-bg-color-error-1);border-radius:.25rem;color:var(--monster-color-error-1);display:inline-block;font-size:75%;font-weight:700;line-height:1;text-align:center;text-decoration:none;vertical-align:baseline;white-space:nowrap}.monster-badge-error-pill{border-radius:10rem;padding:.25em .6em}div[data-monster-role=popper]{align-content:center;background:var(--monster-bg-color-primary-1);border-color:var(--monster-bg-color-primary-4);border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);box-shadow:var(--monster-box-shadow-1);box-sizing:border-box;color:var(--monster-color-primary-1);display:none;justify-content:space-between;left:0;padding:1.1em;position:absolute;top:0;width:-moz-max-content;width:max-content;z-index:var(--monster-z-index-modal)}div[data-monster-role=popper] div[data-monster-role=arrow]{background:var(--monster-bg-color-primary-1);height:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);pointer-events:none;position:absolute;width:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);z-index:-1}[data-monster-role=container]{container-name:field-set;container-type:inline-size;font-size:1rem;font-weight:400;line-height:1.6;margin-bottom:1rem}.collapse-alignment{padding:0 1rem}[data-monster-role=header]{align-items:center;border-bottom:var(--monster-border-width) var(--monster-border-style) var(--monster-color-primary-1);display:flex;justify-content:space-between;margin-bottom:1rem;padding-bottom:.2rem}[data-monster-role=header] label{font-size:1rem;font-weight:400;line-height:1.6;padding-right:.3rem}[data-monster-role=header] [data-monster-role=extended-switch]{align-items:center;display:flex;justify-content:flex-end;padding-right:1rem}[data-monster-role=header] [data-monster-role=title]{font-weight:700;padding-left:1rem}.hidden{display:none!important}slot{display:grid;grid-template-columns:10em 1fr;grid-gap:.8rem;accent-color:var(--monster-color-secondary-2)}.multiple-columns slot{grid-template-columns:auto 1fr auto 1fr auto 1fr}::slotted(.label),::slotted(label){border-bottom:thin dotted var(--monster-color-primary-1);color:var(--monster-color-primary-1)}::slotted(h1),::slotted(h2),::slotted(h3),::slotted(h4),::slotted(h5),::slotted(h6){grid-column:1/3}::slotted(monster-api-button),::slotted(monster-button),::slotted(monster-datasource-save-button),::slotted(monster-select),::slotted(monster-state-button){grid-column:2}::slotted(input){align-self:end}::slotted(monster-toggle-switch){width:4.5rem}.multiple-columns ::slotted(.span-1){grid-column:2/span 3}.multiple-columns ::slotted(.span-1-max){grid-column:2/span 5}.multiple-columns ::slotted(.span-2){grid-column:4/span 3}@container field-set (max-width: 1200px){.multiple-columns slot{grid-template-columns:auto 1fr auto 1fr}.multiple-columns ::slotted(.span-1){grid-column:2/span 3}.multiple-columns ::slotted(.span-2){grid-column:unset}.multiple-columns ::slotted(.span-1-max:first-child){grid-column:2/span 3}}@container field-set (max-width: 800px){.multiple-columns slot{grid-template-columns:auto 1fr}.multiple-columns ::slotted(.span-1){grid-column:unset}.multiple-columns ::slotted(.span-2){grid-column:unset}.multiple-columns ::slotted(.span-1-max){grid-column:unset}}@container field-set (max-width: 500px){slot{gap:0;grid-template-columns:1fr}::slotted(h1),::slotted(h2),::slotted(h3),::slotted(h4),::slotted(h5),::slotted(h6){grid-column:1}::slotted(.label),::slotted(label){border-bottom:none;padding-top:1rem}::slotted(monster-api-button),::slotted(monster-button),::slotted(monster-datasource-save-button),::slotted(monster-state-button){grid-column:1}.multiple-columns slot{grid-template-columns:1fr}.multiple-columns ::slotted(.span-1-max){grid-column:unset}} -}`, 0); +}`, + 0, + ); } catch (e) { - addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + ""); + addAttributeToken( + document.getRootNode().querySelector("html"), + ATTRIBUTE_ERRORMESSAGE, + e + "", + ); } diff --git a/source/components/form/toggle-switch.mjs b/source/components/form/toggle-switch.mjs index 7fbf692e7f2233a8031758f9aa976f331944790d..1e3521e0702b39ff0a04d3edaf883cb4d56a9c0a 100644 --- a/source/components/form/toggle-switch.mjs +++ b/source/components/form/toggle-switch.mjs @@ -12,26 +12,26 @@ * SPDX-License-Identifier: AGPL-3.0 */ -import {instanceSymbol} from "../../constants.mjs"; -import {internalSymbol} from "../../constants.mjs"; -import {CustomControl} from "../../dom/customcontrol.mjs"; -import {Observer} from "../../types/observer.mjs"; -import {ProxyObserver} from "../../types/proxyobserver.mjs"; +import { instanceSymbol } from "../../constants.mjs"; +import { internalSymbol } from "../../constants.mjs"; +import { CustomControl } from "../../dom/customcontrol.mjs"; +import { Observer } from "../../types/observer.mjs"; +import { ProxyObserver } from "../../types/proxyobserver.mjs"; -import {addAttributeToken} from "../../dom/attributes.mjs"; +import { addAttributeToken } from "../../dom/attributes.mjs"; import { - assembleMethodSymbol, - registerCustomElement, - updaterTransformerMethodsSymbol, + assembleMethodSymbol, + registerCustomElement, + updaterTransformerMethodsSymbol, } from "../../dom/customelement.mjs"; -import {isObject, isFunction} from "../../types/is.mjs"; -import {ToggleSwitchStyleSheet} from "./stylesheet/toggle-switch.mjs"; +import { isObject, isFunction } from "../../types/is.mjs"; +import { ToggleSwitchStyleSheet } from "./stylesheet/toggle-switch.mjs"; import { - ATTRIBUTE_ERRORMESSAGE, - ATTRIBUTE_ROLE, + ATTRIBUTE_ERRORMESSAGE, + ATTRIBUTE_ROLE, } from "../../dom/constants.mjs"; -export {ToggleSwitch}; +export { ToggleSwitch }; /** * @private @@ -65,340 +65,340 @@ export const STATE_OFF = "off"; * @fires monster-changed */ class ToggleSwitch extends CustomControl { - /** - * To set the options via the HTML tag, the attribute `data-monster-options` must be used. - * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} - * - * The individual configuration values can be found in the table. - * - * @property {string} value=current value of the element - * @property {Boolean} disabled=disabled=false Disabled state - * @property {Object} classes - * @property {string} classes.on=specifies the class for the on state. - * @property {string} classes.off=specifies the class for the off state. - * @property {Object} values - * @property {string} values.off=specifies the value of the element if it is not selected - * @property {Object} labels - * @property {string} labels.on=specifies the label for the on state. - * @property {string} labels.off=specifies the label for the off state. - * @property {string} actions - * @property {string} actions.on=specifies the action for the on state. - * @property {string} actions.off=specifies the action for the off state. - * @property {Object} templates - * @property {string} templates.main=specifies the main template used by the control. - */ - get defaults() { - return Object.assign({}, super.defaults, { - value: null, - disabled: false, - classes: { - on: "monster-theme-on", - off: "monster-theme-off", - handle: "monster-theme-primary-1", - }, - values: { - on: "on", - off: "off", - }, - labels: { - toggleSwitchOn: "✔", - toggleSwitchOff: "✖", - }, - templates: { - main: getTemplate(), - }, - actions: { - on: () => { - throw new Error("the on action is not defined"); - }, - off: () => { - throw new Error("the off action is not defined"); - }, - }, - }); - } - - /** - * @return {ToggleSwitch} - */ - [assembleMethodSymbol]() { - const self = this; - super[assembleMethodSymbol](); - initControlReferences.call(this); - initEventHandler.call(this); - - /** - * init value to off - * if the value was not defined before inserting it into the HTML - */ - if (self.getOption("value") === null) { - self.setOption("value", self.getOption("values.off")); - } - - /** - * value from attribute - */ - if (self.hasAttribute("value")) { - self.setOption("value", self.getAttribute("value")); - } - - /** - * validate value - */ - validateAndSetValue.call(self); - - if (this.state === STATE_ON) { - toggleClassOn.call(self); - } else { - toggleClassOff.call(self); - } - - /** - * is called when options changed - */ - self[internalSymbol].attachObserver( - new Observer(function () { - if (isObject(this) && this instanceof ProxyObserver) { - validateAndSetValue.call(self); - toggleClass.call(self); - } - }), - ); - - return this; - } - - /** - * updater transformer methods for pipe - * - * @return {function} - */ - [updaterTransformerMethodsSymbol]() { - return { - "state-callback": (Wert) => { - return this.state; - }, - }; - } - - /** - * @return [CSSStyleSheet] - */ - static getCSSStyleSheet() { - return [ToggleSwitchStyleSheet]; - } - - /** - * toggle switch - * - * ``` - * e = document.querySelector('monster-toggle-switch'); - * e.click() - * ``` - */ - click() { - toggleValues.call(this); - } - - /** - * toggle switch on/off - * - * ``` - * e = document.querySelector('monster-toggle-switch'); - * e.toggle() - * ``` - * - * @return {ToggleSwitch} - */ - toggle() { - this.click(); - return this; - } - - /** - * toggle switch on - * - * ``` - * e = document.querySelector('monster-toggle-switch'); - * e.toggleOn() - * ``` - * - * @return {ToggleSwitch} - */ - toggleOn() { - this.setOption("value", this.getOption("values.on")); - return this; - } - - /** - * toggle switch off - * - * ``` - * e = document.querySelector('monster-toggle-switch'); - * e.toggleOff() - * ``` - * - * @return {ToggleSwitch} - */ - toggleOff() { - this.setOption("value", this.getOption("values.off")); - return this; - } - - /** - * returns the status of the element - * - * ``` - * e = document.querySelector('monster-toggle-switch'); - * console.log(e.state) - * // ↦ off - * ``` - * - * @return {string} - */ - get state() { - return this.getOption("value") === this.getOption("values.on") - ? STATE_ON - : STATE_OFF; - } - - /** - * The current value of the Switch - * - * ``` - * e = document.querySelector('monster-toggle-switch'); - * console.log(e.value) - * // ↦ on - * ``` - * - * @return {string} - */ - get value() { - return this.state === STATE_ON - ? this.getOption("values.on") - : this.getOption("values.off"); - } - - /** - * Set value - * - * ``` - * e = document.querySelector('monster-toggle-switch'); - * e.value="on" - * ``` - * - * @property {string} value - */ - set value(value) { - this.setOption("value", value); - } - - /** - * This method is called by the `instanceof` operator. - * @returns {symbol} - */ - static get [instanceSymbol]() { - return Symbol.for( - "@schukai/monster/components/form/toggle-switch@@instance", - ); - } - - static getTag() { - return "monster-toggle-switch"; - } + /** + * To set the options via the HTML tag, the attribute `data-monster-options` must be used. + * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} + * + * The individual configuration values can be found in the table. + * + * @property {string} value=current value of the element + * @property {Boolean} disabled=disabled=false Disabled state + * @property {Object} classes + * @property {string} classes.on=specifies the class for the on state. + * @property {string} classes.off=specifies the class for the off state. + * @property {Object} values + * @property {string} values.off=specifies the value of the element if it is not selected + * @property {Object} labels + * @property {string} labels.on=specifies the label for the on state. + * @property {string} labels.off=specifies the label for the off state. + * @property {string} actions + * @property {string} actions.on=specifies the action for the on state. + * @property {string} actions.off=specifies the action for the off state. + * @property {Object} templates + * @property {string} templates.main=specifies the main template used by the control. + */ + get defaults() { + return Object.assign({}, super.defaults, { + value: null, + disabled: false, + classes: { + on: "monster-theme-on", + off: "monster-theme-off", + handle: "monster-theme-primary-1", + }, + values: { + on: "on", + off: "off", + }, + labels: { + toggleSwitchOn: "✔", + toggleSwitchOff: "✖", + }, + templates: { + main: getTemplate(), + }, + actions: { + on: () => { + throw new Error("the on action is not defined"); + }, + off: () => { + throw new Error("the off action is not defined"); + }, + }, + }); + } + + /** + * @return {ToggleSwitch} + */ + [assembleMethodSymbol]() { + const self = this; + super[assembleMethodSymbol](); + initControlReferences.call(this); + initEventHandler.call(this); + + /** + * init value to off + * if the value was not defined before inserting it into the HTML + */ + if (self.getOption("value") === null) { + self.setOption("value", self.getOption("values.off")); + } + + /** + * value from attribute + */ + if (self.hasAttribute("value")) { + self.setOption("value", self.getAttribute("value")); + } + + /** + * validate value + */ + validateAndSetValue.call(self); + + if (this.state === STATE_ON) { + toggleClassOn.call(self); + } else { + toggleClassOff.call(self); + } + + /** + * is called when options changed + */ + self[internalSymbol].attachObserver( + new Observer(function () { + if (isObject(this) && this instanceof ProxyObserver) { + validateAndSetValue.call(self); + toggleClass.call(self); + } + }), + ); + + return this; + } + + /** + * updater transformer methods for pipe + * + * @return {function} + */ + [updaterTransformerMethodsSymbol]() { + return { + "state-callback": (Wert) => { + return this.state; + }, + }; + } + + /** + * @return [CSSStyleSheet] + */ + static getCSSStyleSheet() { + return [ToggleSwitchStyleSheet]; + } + + /** + * toggle switch + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * e.click() + * ``` + */ + click() { + toggleValues.call(this); + } + + /** + * toggle switch on/off + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * e.toggle() + * ``` + * + * @return {ToggleSwitch} + */ + toggle() { + this.click(); + return this; + } + + /** + * toggle switch on + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * e.toggleOn() + * ``` + * + * @return {ToggleSwitch} + */ + toggleOn() { + this.setOption("value", this.getOption("values.on")); + return this; + } + + /** + * toggle switch off + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * e.toggleOff() + * ``` + * + * @return {ToggleSwitch} + */ + toggleOff() { + this.setOption("value", this.getOption("values.off")); + return this; + } + + /** + * returns the status of the element + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * console.log(e.state) + * // ↦ off + * ``` + * + * @return {string} + */ + get state() { + return this.getOption("value") === this.getOption("values.on") + ? STATE_ON + : STATE_OFF; + } + + /** + * The current value of the Switch + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * console.log(e.value) + * // ↦ on + * ``` + * + * @return {string} + */ + get value() { + return this.state === STATE_ON + ? this.getOption("values.on") + : this.getOption("values.off"); + } + + /** + * Set value + * + * ``` + * e = document.querySelector('monster-toggle-switch'); + * e.value="on" + * ``` + * + * @property {string} value + */ + set value(value) { + this.setOption("value", value); + } + + /** + * This method is called by the `instanceof` operator. + * @returns {symbol} + */ + static get [instanceSymbol]() { + return Symbol.for( + "@schukai/monster/components/form/toggle-switch@@instance", + ); + } + + static getTag() { + return "monster-toggle-switch"; + } } /** * @private */ function initControlReferences() { - this[switchElementSymbol] = this.shadowRoot.querySelector( - `[${ATTRIBUTE_ROLE}=switch]`, - ); + this[switchElementSymbol] = this.shadowRoot.querySelector( + `[${ATTRIBUTE_ROLE}=switch]`, + ); } /** * @private */ function toggleClassOn() { - this[switchElementSymbol].classList.remove(this.getOption("classes.off")); // change color - this[switchElementSymbol].classList.add(this.getOption("classes.on")); // change color + this[switchElementSymbol].classList.remove(this.getOption("classes.off")); // change color + this[switchElementSymbol].classList.add(this.getOption("classes.on")); // change color } /** * @private */ function toggleClassOff() { - this[switchElementSymbol].classList.remove(this.getOption("classes.on")); // change color - this[switchElementSymbol].classList.add(this.getOption("classes.off")); // change color + this[switchElementSymbol].classList.remove(this.getOption("classes.on")); // change color + this[switchElementSymbol].classList.add(this.getOption("classes.off")); // change color } /** * @private */ function toggleClass() { - if (this.getOption("value") === this.getOption("values.on")) { - toggleClassOn.call(this); - } else { - toggleClassOff.call(this); - } + if (this.getOption("value") === this.getOption("values.on")) { + toggleClassOn.call(this); + } else { + toggleClassOff.call(this); + } } /** * @private */ function toggleValues() { - if (this.getOption("disabled") === true) { - return; - } + if (this.getOption("disabled") === true) { + return; + } - let callback, value; + let callback, value; - if (this.getOption("value") === this.getOption("values.on")) { - value = this.getOption("values.off"); - callback = this.getOption("actions.off"); - } else { - value = this.getOption("values.on"); - callback = this.getOption("actions.on"); - } + if (this.getOption("value") === this.getOption("values.on")) { + value = this.getOption("values.off"); + callback = this.getOption("actions.off"); + } else { + value = this.getOption("values.on"); + callback = this.getOption("actions.on"); + } - this.setOption("value", value); - this?.setFormValue(value); + this.setOption("value", value); + this?.setFormValue(value); - if (isFunction(callback)) { - callback.call(this); - } + if (isFunction(callback)) { + callback.call(this); + } - this.setOption("state", this.state); + this.setOption("state", this.state); } /** * @private */ function validateAndSetValue() { - const value = this.getOption("value"); - - const validatedValues = []; - validatedValues.push(this.getOption("values.on")); - validatedValues.push(this.getOption("values.off")); - - if (validatedValues.includes(value) === false) { - addAttributeToken( - this, - ATTRIBUTE_ERRORMESSAGE, - 'The value "' + - value + - '" must be "' + - this.getOption("values.on") + - '" or "' + - this.getOption("values.off"), - ); - this.setOption("disabled", true); - this.formDisabledCallback(true); - } else { - this.setOption("disabled", false); - this.formDisabledCallback(false); - } + const value = this.getOption("value"); + + const validatedValues = []; + validatedValues.push(this.getOption("values.on")); + validatedValues.push(this.getOption("values.off")); + + if (validatedValues.includes(value) === false) { + addAttributeToken( + this, + ATTRIBUTE_ERRORMESSAGE, + 'The value "' + + value + + '" must be "' + + this.getOption("values.on") + + '" or "' + + this.getOption("values.off"), + ); + this.setOption("disabled", true); + this.formDisabledCallback(true); + } else { + this.setOption("disabled", false); + this.formDisabledCallback(false); + } } /** @@ -406,16 +406,16 @@ function validateAndSetValue() { * @return {initEventHandler} */ function initEventHandler() { - const self = this; - self.addEventListener("keyup", function (event) { - if (event.code === "Space") { - self[switchElementSymbol].click(); - } - }); - self.addEventListener("click", function (event) { - toggleValues.call(self); - }); - return this; + const self = this; + self.addEventListener("keyup", function (event) { + if (event.code === "Space") { + self[switchElementSymbol].click(); + } + }); + self.addEventListener("click", function (event) { + toggleValues.call(self); + }); + return this; } /** @@ -423,8 +423,8 @@ function initEventHandler() { * @return {string} */ function getTemplate() { - // language=HTML - return ` + // language=HTML + return ` <div data-monster-role="control" part="control" tabindex="0"> <div class="switch" data-monster-role="switch" data-monster-attributes="data-monster-state path:value | call:state-callback"> diff --git a/source/components/layout/collapse.mjs b/source/components/layout/collapse.mjs index 8ea0fd61ff628ca71395ba9ee432f90d18d7f43f..65e687f3e878cc76b41db63e9e5e45858cd7ff9a 100644 --- a/source/components/layout/collapse.mjs +++ b/source/components/layout/collapse.mjs @@ -13,22 +13,22 @@ */ import { - assembleMethodSymbol, - CustomElement, - getSlottedElements, - registerCustomElement, + assembleMethodSymbol, + CustomElement, + getSlottedElements, + registerCustomElement, } from "../../dom/customelement.mjs"; -import {CollapseStyleSheet} from "./stylesheet/collapse.mjs"; -import {fireCustomEvent} from "../../dom/events.mjs"; -import {getDocument} from "../../dom/util.mjs"; -import {addAttributeToken} from "../../dom/attributes.mjs"; -import {ATTRIBUTE_ERRORMESSAGE} from "../../dom/constants.mjs"; -import {Host} from "../host/host.mjs"; -import {generateUniqueConfigKey} from "../host/util.mjs"; -import {DeadMansSwitch} from "../../util/deadmansswitch.mjs"; -import {instanceSymbol} from "../../constants.mjs"; - -export {Collapse, nameSymbol}; +import { CollapseStyleSheet } from "./stylesheet/collapse.mjs"; +import { fireCustomEvent } from "../../dom/events.mjs"; +import { getDocument } from "../../dom/util.mjs"; +import { addAttributeToken } from "../../dom/attributes.mjs"; +import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs"; +import { Host } from "../host/host.mjs"; +import { generateUniqueConfigKey } from "../host/util.mjs"; +import { DeadMansSwitch } from "../../util/deadmansswitch.mjs"; +import { instanceSymbol } from "../../constants.mjs"; + +export { Collapse, nameSymbol }; /** * @private @@ -91,205 +91,205 @@ const nameSymbol = Symbol("name"); * @summary A simple collapse component. */ class Collapse extends CustomElement { - /** - * This method is called by the `instanceof` operator. - * @returns {symbol} - */ - static get [instanceSymbol]() { - return Symbol.for("@schukai/monster/components/layout/collapse@@instance"); - } - - /** - * - */ - constructor() { - super(); - // the name is only used for the host config and the event name - this[nameSymbol] = "collapse"; - } - - /** - * To set the options via the HTML tag, the attribute `data-monster-options` must be used. - * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} - * - * The individual configuration values can be found in the table. - * - * @property {Object} templates Template definitions - * @property {string} templates.main Main template - * @property {Object} classes CSS classes - * @property {string} classes.container CSS class for the container - * @property {Object} features Feature configuration - * @property {boolean} features.accordion Enable accordion mode - * @property {boolean} features.persistState Enable persist state (Host and Config-Manager required) - * @property {boolean} features.useScrollValues Use scroll values (scrollHeight) instead of clientHeight for the height calculation - * @property {boolean} openByDefault Open the details by default - */ - get defaults() { - return Object.assign({}, super.defaults, { - templates: { - main: getTemplate(), - }, - classes: { - container: "padding", - }, - features: { - accordion: true, - persistState: true, - useScrollValues: false, - }, - openByDefault: false, - }); - } - - /** - * - * @returns {void} - */ - [assembleMethodSymbol]() { - super[assembleMethodSymbol](); - initControlReferences.call(this); - initStateFromHostConfig.call(this); - initResizeObserver.call(this); - initEventHandler.call(this); - - if (this.getOption("openByDefault")) { - this.open(); - } - } - - /** - * @returns {void} - */ - connectedCallback() { - super.connectedCallback(); - updateResizeObserverObservation.call(this); - } - - /** - * @returns {void} - */ - disconnectedCallback() { - super.disconnectedCallback(); - } - - /** - * @returns {Collapse} - */ - toggle() { - if (this[detailsElementSymbol].classList.contains("active")) { - this.close(); - } else { - this.open(); - } - return this; - } - - /** - * @returns {boolean} - */ - isClosed() { - return !this[detailsElementSymbol].classList.contains("active"); - } - - /** - * @returns {boolean} - */ - isOpen() { - return !this.isClosed(); - } - - /** - * Open the collapse - * @returns {Collapse} - * @fires event:monster-collapse-before-open - * @fires event:monster-collapse-open - */ - open() { - let node; - if (this[detailsElementSymbol].classList.contains("active")) { - return this; - } - - fireCustomEvent(this, "monster-" + this[nameSymbol] + "-before-open", {}); - - adjustHeight.call(this); - this[detailsElementSymbol].classList.add("active"); - - if (this.getOption("features.accordion") === true) { - node = this; - while (node.nextElementSibling instanceof Collapse) { - node = node.nextElementSibling; - node.close(); - } - - node = this; - while (node.previousElementSibling instanceof Collapse) { - node = node.previousElementSibling; - node.close(); - } - } - - setTimeout(() => { - setTimeout(() => { - updateStateConfig.call(this); - fireCustomEvent(this, "monster-" + this[nameSymbol] + "-open", {}); - setTimeout(() => { - this[controlElementSymbol].classList.remove("overflow-hidden"); - }, 500); - }, 0); - }, 0); - - return this; - } - - /** - * Close the collapse - * @returns {Collapse} - * @fires event:monster-collapse-before-close - * @fires event:monster-collapse-closed - */ - close() { - if (!this[detailsElementSymbol].classList.contains("active")) { - return this; - } - - fireCustomEvent(this, "monster-" + this[nameSymbol] + "-before-close", {}); - this[controlElementSymbol].classList.add("overflow-hidden"); - - setTimeout(() => { - this[detailsElementSymbol].classList.remove("active"); - setTimeout(() => { - updateStateConfig.call(this); - fireCustomEvent(this, "monster-" + this[nameSymbol] + "-closed", {}); - }, 0); - }, 0); - - return this; - } - - /** - * @return {string} - */ - static getTag() { - return "monster-collapse"; - } - - /** - * @return {Array<CSSStyleSheet>} - */ - static getCSSStyleSheet() { - return [CollapseStyleSheet]; - } - - /** - * This method is called when the element is inserted into a document, including into a shadow tree. - * @return {Collapse} - * @fires event:monster-collapse-adjust-height - */ - adjustHeight() { - adjustHeight.call(this); - return this; - } + /** + * This method is called by the `instanceof` operator. + * @returns {symbol} + */ + static get [instanceSymbol]() { + return Symbol.for("@schukai/monster/components/layout/collapse@@instance"); + } + + /** + * + */ + constructor() { + super(); + // the name is only used for the host config and the event name + this[nameSymbol] = "collapse"; + } + + /** + * To set the options via the HTML tag, the attribute `data-monster-options` must be used. + * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} + * + * The individual configuration values can be found in the table. + * + * @property {Object} templates Template definitions + * @property {string} templates.main Main template + * @property {Object} classes CSS classes + * @property {string} classes.container CSS class for the container + * @property {Object} features Feature configuration + * @property {boolean} features.accordion Enable accordion mode + * @property {boolean} features.persistState Enable persist state (Host and Config-Manager required) + * @property {boolean} features.useScrollValues Use scroll values (scrollHeight) instead of clientHeight for the height calculation + * @property {boolean} openByDefault Open the details by default + */ + get defaults() { + return Object.assign({}, super.defaults, { + templates: { + main: getTemplate(), + }, + classes: { + container: "padding", + }, + features: { + accordion: true, + persistState: true, + useScrollValues: false, + }, + openByDefault: false, + }); + } + + /** + * + * @returns {void} + */ + [assembleMethodSymbol]() { + super[assembleMethodSymbol](); + initControlReferences.call(this); + initStateFromHostConfig.call(this); + initResizeObserver.call(this); + initEventHandler.call(this); + + if (this.getOption("openByDefault")) { + this.open(); + } + } + + /** + * @returns {void} + */ + connectedCallback() { + super.connectedCallback(); + updateResizeObserverObservation.call(this); + } + + /** + * @returns {void} + */ + disconnectedCallback() { + super.disconnectedCallback(); + } + + /** + * @returns {Collapse} + */ + toggle() { + if (this[detailsElementSymbol].classList.contains("active")) { + this.close(); + } else { + this.open(); + } + return this; + } + + /** + * @returns {boolean} + */ + isClosed() { + return !this[detailsElementSymbol].classList.contains("active"); + } + + /** + * @returns {boolean} + */ + isOpen() { + return !this.isClosed(); + } + + /** + * Open the collapse + * @returns {Collapse} + * @fires event:monster-collapse-before-open + * @fires event:monster-collapse-open + */ + open() { + let node; + if (this[detailsElementSymbol].classList.contains("active")) { + return this; + } + + fireCustomEvent(this, "monster-" + this[nameSymbol] + "-before-open", {}); + + adjustHeight.call(this); + this[detailsElementSymbol].classList.add("active"); + + if (this.getOption("features.accordion") === true) { + node = this; + while (node.nextElementSibling instanceof Collapse) { + node = node.nextElementSibling; + node.close(); + } + + node = this; + while (node.previousElementSibling instanceof Collapse) { + node = node.previousElementSibling; + node.close(); + } + } + + setTimeout(() => { + setTimeout(() => { + updateStateConfig.call(this); + fireCustomEvent(this, "monster-" + this[nameSymbol] + "-open", {}); + setTimeout(() => { + this[controlElementSymbol].classList.remove("overflow-hidden"); + }, 500); + }, 0); + }, 0); + + return this; + } + + /** + * Close the collapse + * @returns {Collapse} + * @fires event:monster-collapse-before-close + * @fires event:monster-collapse-closed + */ + close() { + if (!this[detailsElementSymbol].classList.contains("active")) { + return this; + } + + fireCustomEvent(this, "monster-" + this[nameSymbol] + "-before-close", {}); + this[controlElementSymbol].classList.add("overflow-hidden"); + + setTimeout(() => { + this[detailsElementSymbol].classList.remove("active"); + setTimeout(() => { + updateStateConfig.call(this); + fireCustomEvent(this, "monster-" + this[nameSymbol] + "-closed", {}); + }, 0); + }, 0); + + return this; + } + + /** + * @return {string} + */ + static getTag() { + return "monster-collapse"; + } + + /** + * @return {Array<CSSStyleSheet>} + */ + static getCSSStyleSheet() { + return [CollapseStyleSheet]; + } + + /** + * This method is called when the element is inserted into a document, including into a shadow tree. + * @return {Collapse} + * @fires event:monster-collapse-adjust-height + */ + adjustHeight() { + adjustHeight.call(this); + return this; + } } /** @@ -298,78 +298,78 @@ class Collapse extends CustomElement { * @fires event:monster-collapse-adjust-height */ function adjustHeight() { - let height = 0; - - if (this[detailsContainerElementSymbol]) { - if (this.getOption("features.useScrollValues")) { - height += this[detailsContainerElementSymbol].scrollHeight; - } else { - height += this[detailsContainerElementSymbol].clientHeight; - } - } - - if (this[detailsDecoElementSymbol]) { - if (this.getOption("features.useScrollValues")) { - height += this[detailsDecoElementSymbol].scrollHeight; - } else { - height += this[detailsDecoElementSymbol].clientHeight + 1; - } - } - - if (height === 0) { - if (this.getOption("features.useScrollValues")) { - height = this[detailsElementSymbol].scrollHeight; - } else { - height = this[detailsElementSymbol].clientHeight; - } - - if (height === 0) { - height = "auto"; - } - } else { - height += "px"; - } - - this[detailsElementSymbol].style.setProperty( - "--monster-height", - height, - "important", - ); - - fireCustomEvent(this, "monster-" + this[nameSymbol] + "-adjust-height", {}); + let height = 0; + + if (this[detailsContainerElementSymbol]) { + if (this.getOption("features.useScrollValues")) { + height += this[detailsContainerElementSymbol].scrollHeight; + } else { + height += this[detailsContainerElementSymbol].clientHeight; + } + } + + if (this[detailsDecoElementSymbol]) { + if (this.getOption("features.useScrollValues")) { + height += this[detailsDecoElementSymbol].scrollHeight; + } else { + height += this[detailsDecoElementSymbol].clientHeight + 1; + } + } + + if (height === 0) { + if (this.getOption("features.useScrollValues")) { + height = this[detailsElementSymbol].scrollHeight; + } else { + height = this[detailsElementSymbol].clientHeight; + } + + if (height === 0) { + height = "auto"; + } + } else { + height += "px"; + } + + this[detailsElementSymbol].style.setProperty( + "--monster-height", + height, + "important", + ); + + fireCustomEvent(this, "monster-" + this[nameSymbol] + "-adjust-height", {}); } function updateResizeObserverObservation() { - this[resizeObserverSymbol].disconnect(); + this[resizeObserverSymbol].disconnect(); - const slottedNodes = getSlottedElements.call(this); - slottedNodes.forEach((node) => { - this[resizeObserverSymbol].observe(node); - }); + const slottedNodes = getSlottedElements.call(this); + slottedNodes.forEach((node) => { + this[resizeObserverSymbol].observe(node); + }); - if (this[detailsContainerElementSymbol]) { - this[resizeObserverSymbol].observe(this[detailsContainerElementSymbol]); - } + if (this[detailsContainerElementSymbol]) { + this[resizeObserverSymbol].observe(this[detailsContainerElementSymbol]); + } - this.adjustHeight(); + this.adjustHeight(); } /** * @private */ function initEventHandler() { - if (!this.shadowRoot) { - throw new Error("no shadow-root is defined"); - } + if (!this.shadowRoot) { + throw new Error("no shadow-root is defined"); + } - initSlotChangedHandler.call(this); - return this; + initSlotChangedHandler.call(this); + return this; } function initSlotChangedHandler() { - this[detailsSlotElementSymbol].addEventListener("slotchange", () => { - updateResizeObserverObservation.call(this); - }); + this[detailsSlotElementSymbol].addEventListener("slotchange", () => { + updateResizeObserverObservation.call(this); + }); } /** @@ -378,23 +378,23 @@ function initSlotChangedHandler() { * @throws {Error} no shadow-root is defined */ function initControlReferences() { - if (!this.shadowRoot) { - throw new Error("no shadow-root is defined"); - } - - this[controlElementSymbol] = this.shadowRoot.querySelector( - "[data-monster-role=control]", - ); - this[detailsElementSymbol] = this.shadowRoot.querySelector( - "[data-monster-role=detail]", - ); - this[detailsSlotElementSymbol] = this.shadowRoot.querySelector("slot"); - this[detailsContainerElementSymbol] = this.shadowRoot.querySelector( - "[data-monster-role=container]", - ); - this[detailsDecoElementSymbol] = this.shadowRoot.querySelector( - "[data-monster-role=deco]", - ); + if (!this.shadowRoot) { + throw new Error("no shadow-root is defined"); + } + + this[controlElementSymbol] = this.shadowRoot.querySelector( + "[data-monster-role=control]", + ); + this[detailsElementSymbol] = this.shadowRoot.querySelector( + "[data-monster-role=detail]", + ); + this[detailsSlotElementSymbol] = this.shadowRoot.querySelector("slot"); + this[detailsContainerElementSymbol] = this.shadowRoot.querySelector( + "[data-monster-role=container]", + ); + this[detailsDecoElementSymbol] = this.shadowRoot.querySelector( + "[data-monster-role=deco]", + ); } /** @@ -402,34 +402,34 @@ function initControlReferences() { * @returns {string} */ function getConfigKey() { - return generateUniqueConfigKey(this[nameSymbol], this.id, "state"); + return generateUniqueConfigKey(this[nameSymbol], this.id, "state"); } /** * @private */ function updateStateConfig() { - if (!this.getOption("features.persistState")) { - return; - } - - if (!this[detailsElementSymbol]) { - return; - } - - const document = getDocument(); - const host = document.querySelector("monster-host"); - if (!(host && this.id)) { - return; - } - - const configKey = getConfigKey.call(this); - - try { - host.setConfig(configKey, this.isOpen()); - } catch (error) { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error)); - } + if (!this.getOption("features.persistState")) { + return; + } + + if (!this[detailsElementSymbol]) { + return; + } + + const document = getDocument(); + const host = document.querySelector("monster-host"); + if (!(host && this.id)) { + return; + } + + const configKey = getConfigKey.call(this); + + try { + host.setConfig(configKey, this.isOpen()); + } catch (error) { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error)); + } } /** @@ -437,55 +437,55 @@ function updateStateConfig() { * @returns {Promise} */ function initStateFromHostConfig() { - if (!this.getOption("features.persistState")) { - return Promise.resolve({}); - } - - const document = getDocument(); - const host = document.querySelector("monster-host"); - - if (!(host && this.id)) { - return Promise.resolve({}); - } - - const configKey = getConfigKey.call(this); - return host - .getConfig(configKey) - .then((state) => { - if (state === true) { - this.open(); - } else { - this.close(); - } - }) - .catch((error) => { - addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString()); - }); + if (!this.getOption("features.persistState")) { + return Promise.resolve({}); + } + + const document = getDocument(); + const host = document.querySelector("monster-host"); + + if (!(host && this.id)) { + return Promise.resolve({}); + } + + const configKey = getConfigKey.call(this); + return host + .getConfig(configKey) + .then((state) => { + if (state === true) { + this.open(); + } else { + this.close(); + } + }) + .catch((error) => { + addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString()); + }); } /** * @private */ function initResizeObserver() { - // against flickering - this[resizeObserverSymbol] = new ResizeObserver((entries) => { - if (this[timerCallbackSymbol] instanceof DeadMansSwitch) { - try { - this[timerCallbackSymbol].touch(); - return; - } catch (e) { - delete this[timerCallbackSymbol]; - } - } - - this[timerCallbackSymbol] = new DeadMansSwitch(200, () => { - checkAndRearrangeContent.call(this); - }); - }); + // against flickering + this[resizeObserverSymbol] = new ResizeObserver((entries) => { + if (this[timerCallbackSymbol] instanceof DeadMansSwitch) { + try { + this[timerCallbackSymbol].touch(); + return; + } catch (e) { + delete this[timerCallbackSymbol]; + } + } + + this[timerCallbackSymbol] = new DeadMansSwitch(200, () => { + checkAndRearrangeContent.call(this); + }); + }); } function checkAndRearrangeContent() { - this.adjustHeight(); + this.adjustHeight(); } /** @@ -493,8 +493,8 @@ function checkAndRearrangeContent() { * @return {string} */ function getTemplate() { - // language=HTML - return ` + // language=HTML + return ` <div data-monster-role="control" part="control" class="overflow-hidden"> <div data-monster-role="detail"> <div data-monster-attributes="class path:classes.container" part="container" diff --git a/source/components/layout/details.mjs b/source/components/layout/details.mjs index 8ea5a43d1e48eb278adaa899308fcb37b01686e1..d1af73b60e2f9e4d01449f86676de0ca4a81ee60 100644 --- a/source/components/layout/details.mjs +++ b/source/components/layout/details.mjs @@ -188,7 +188,7 @@ function initButtonLabel() { label = ""; } - if (label==="") { + if (label === "") { label = this.innerText; } diff --git a/source/components/layout/iframe.mjs b/source/components/layout/iframe.mjs index fc8a02fcc77013b24343f8b642688187436985fc..13ad44997c560dcaa17e5f4af68bb409da05cb8f 100644 --- a/source/components/layout/iframe.mjs +++ b/source/components/layout/iframe.mjs @@ -61,7 +61,7 @@ const timerCallbackSymbol = Symbol("timerCallback"); * @fragments /fragments/components/layout/iframe/ * * @example /examples/components/layout/iframe-simple - * + * * @since 3.76.0 * @copyright schukai GmbH * @summary A cool and fancy Iframe that can make your life easier and also looks good. diff --git a/source/components/layout/width-toggle.mjs b/source/components/layout/width-toggle.mjs index e4ca81fe93424668847c60c5697fc02b137f44fa..24ed6c8c0b2c767a0686f4b5f059e7dcd7fc61ed 100644 --- a/source/components/layout/width-toggle.mjs +++ b/source/components/layout/width-toggle.mjs @@ -63,8 +63,8 @@ const MODE_WIDE = "wide"; * * @since 3.57.0 * @copyright schukai GmbH - * @summary The WidthToggle component allows users to dynamically change the width of a panel by clicking a button. - * @summary This feature improves readability and space utilization by allowing the panel width to be adjusted + * @summary The WidthToggle component allows users to dynamically change the width of a panel by clicking a button. + * @summary This feature improves readability and space utilization by allowing the panel width to be adjusted * @summary according to user preferences. */ class WidthToggle extends CustomElement { @@ -124,7 +124,6 @@ class WidthToggle extends CustomElement { * @throws {Error} - If the mode is not supported. */ - /** * @param {string} mode * @returns {WidthToggle} diff --git a/source/components/state/log.mjs b/source/components/state/log.mjs index 133f4cccd92493cd0267eee9a8c0def311aab824..23e819551db995d0fc1ef6e54227727739993b59 100644 --- a/source/components/state/log.mjs +++ b/source/components/state/log.mjs @@ -12,19 +12,19 @@ * SPDX-License-Identifier: AGPL-3.0 */ -import {instanceSymbol} from "../../constants.mjs"; +import { instanceSymbol } from "../../constants.mjs"; import { - assembleMethodSymbol, - CustomElement, - getSlottedElements, - registerCustomElement, + assembleMethodSymbol, + CustomElement, + getSlottedElements, + registerCustomElement, } from "../../dom/customelement.mjs"; -import {LogStyleSheet} from "./stylesheet/log.mjs"; -import {Entry} from "./log/entry.mjs"; -import {validateInstance} from "../../types/validate.mjs"; +import { LogStyleSheet } from "./stylesheet/log.mjs"; +import { Entry } from "./log/entry.mjs"; +import { validateInstance } from "../../types/validate.mjs"; import "./state.mjs"; -export {Log}; +export { Log }; /** * @private @@ -72,7 +72,6 @@ const emptyStateElementSymbol = Symbol("emptyStateElement"); * @summary Log is a control to show a log message. */ - /** * A Log component * @@ -85,124 +84,124 @@ const emptyStateElementSymbol = Symbol("emptyStateElement"); * @summary A Log component to show a log message. */ class Log extends CustomElement { - /** - * @return {void} - */ - [assembleMethodSymbol]() { - super[assembleMethodSymbol](); - - initControlReferences.call(this); - initEventHandler.call(this); - } - - /** - * This method is called by the `instanceof` operator. - * @returns {symbol} - */ - static get [instanceSymbol]() { - return Symbol.for("@schukai/monster/components/state/log@@instance"); - } - - /** - * To set the options via the HTML tag, the attribute `data-monster-options` must be used. - * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} - * - * The individual configuration values can be found in the table. - * - * @property {Object} templates Template definitions - * @property {string} templates.main Main template - * @property {Object} labels Labels - * @property {string} labels.nothingToReport Label for empty state - */ - get defaults() { - return Object.assign({}, super.defaults, { - templates: { - main: getTemplate(), - }, - - labels: { - nothingToReport: "There is nothing to report yet.", - }, - - entries: [], - }); - } - - /** - * @return {void} - */ - connectedCallback() { - super.connectedCallback(); - - const slottedElements = getSlottedElements.call(this); - if (slottedElements.size > 0) { - this[emptyStateElementSymbol].style.display = "none"; - } - } - - /** - * Clear the log - * - * @return {Log} - */ - clear() { - this[logElementSymbol].innerHTML = ""; - this[emptyStateElementSymbol].style.display = "block"; - return this; - } - - /** - * Add an entry to the log - * @param entry - * @returns {Log} - */ - addEntry(entry) { - validateInstance(entry, Entry); - - const entries = this.getOption("entries"); - entries.push(entry); - - /** this field is not used, but triggers a change event */ - this.setOption("length", entries.length - 1); - - return this; - } - - /** - * Add a log message - * @param message - * @param date - * @returns {Log} - */ - addMessage(message, date) { - if (!date) { - date = new Date(); - } - - this.addEntry( - new Entry({ - message: message, - date: date, - }), - ); - - return this; - } - - /** - * - * @return {string} - */ - static getTag() { - return "monster-log"; - } - - /** - * @return {CSSStyleSheet[]} - */ - static getCSSStyleSheet() { - return [LogStyleSheet]; - } + /** + * @return {void} + */ + [assembleMethodSymbol]() { + super[assembleMethodSymbol](); + + initControlReferences.call(this); + initEventHandler.call(this); + } + + /** + * This method is called by the `instanceof` operator. + * @returns {symbol} + */ + static get [instanceSymbol]() { + return Symbol.for("@schukai/monster/components/state/log@@instance"); + } + + /** + * To set the options via the HTML tag, the attribute `data-monster-options` must be used. + * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control} + * + * The individual configuration values can be found in the table. + * + * @property {Object} templates Template definitions + * @property {string} templates.main Main template + * @property {Object} labels Labels + * @property {string} labels.nothingToReport Label for empty state + */ + get defaults() { + return Object.assign({}, super.defaults, { + templates: { + main: getTemplate(), + }, + + labels: { + nothingToReport: "There is nothing to report yet.", + }, + + entries: [], + }); + } + + /** + * @return {void} + */ + connectedCallback() { + super.connectedCallback(); + + const slottedElements = getSlottedElements.call(this); + if (slottedElements.size > 0) { + this[emptyStateElementSymbol].style.display = "none"; + } + } + + /** + * Clear the log + * + * @return {Log} + */ + clear() { + this[logElementSymbol].innerHTML = ""; + this[emptyStateElementSymbol].style.display = "block"; + return this; + } + + /** + * Add an entry to the log + * @param entry + * @returns {Log} + */ + addEntry(entry) { + validateInstance(entry, Entry); + + const entries = this.getOption("entries"); + entries.push(entry); + + /** this field is not used, but triggers a change event */ + this.setOption("length", entries.length - 1); + + return this; + } + + /** + * Add a log message + * @param message + * @param date + * @returns {Log} + */ + addMessage(message, date) { + if (!date) { + date = new Date(); + } + + this.addEntry( + new Entry({ + message: message, + date: date, + }), + ); + + return this; + } + + /** + * + * @return {string} + */ + static getTag() { + return "monster-log"; + } + + /** + * @return {CSSStyleSheet[]} + */ + static getCSSStyleSheet() { + return [LogStyleSheet]; + } } /** @@ -211,37 +210,37 @@ class Log extends CustomElement { * @throws {Error} no shadow-root is defined */ function initControlReferences() { - if (!this.shadowRoot) { - throw new Error("no shadow-root is defined"); - } - - this[logElementSymbol] = this.shadowRoot.querySelector( - "[data-monster-role=control]", - ); - this[emptyStateElementSymbol] = this.shadowRoot.querySelector( - "[data-monster-role=empty-state]", - ); + if (!this.shadowRoot) { + throw new Error("no shadow-root is defined"); + } + + this[logElementSymbol] = this.shadowRoot.querySelector( + "[data-monster-role=control]", + ); + this[emptyStateElementSymbol] = this.shadowRoot.querySelector( + "[data-monster-role=empty-state]", + ); } /** * @private */ function initEventHandler() { - if (!this.shadowRoot) { - throw new Error("no shadow-root is defined"); - } + if (!this.shadowRoot) { + throw new Error("no shadow-root is defined"); + } - this.shadowRoot.addEventListener("slotchange", (event) => { - const slottedElements = getSlottedElements.call(this); + this.shadowRoot.addEventListener("slotchange", (event) => { + const slottedElements = getSlottedElements.call(this); - if (slottedElements.size > 0) { - this[emptyStateElementSymbol].style.display = "none"; - } else { - this[emptyStateElementSymbol].style.display = "block"; - } - }); + if (slottedElements.size > 0) { + this[emptyStateElementSymbol].style.display = "none"; + } else { + this[emptyStateElementSymbol].style.display = "block"; + } + }); - return this; + return this; } /** @@ -249,8 +248,8 @@ function initEventHandler() { * @return {string} */ function getTemplate() { - // language=HTML - return ` + // language=HTML + return ` <template id="entry"> <li data-monster-role="entry"> <span></span> diff --git a/source/components/state/state.mjs b/source/components/state/state.mjs index 30401ab19116b27541c8b07430804e3fb5824e45..3a6c43d1d64082ff1592ab1e50cccee443a97e97 100644 --- a/source/components/state/state.mjs +++ b/source/components/state/state.mjs @@ -53,7 +53,7 @@ class State extends CustomControl { * @returns {symbol} */ static get [instanceSymbol]() { - return Symbol.for("@schukai/monster/components/state/state@@instance"); + return Symbol.for("@schukai/monster/components/state/state@@instance"); } /** diff --git a/source/components/stylesheet/form.mjs b/source/components/stylesheet/form.mjs index 0a954a6f47d49be85a0ca95badfcb033924ac182..2b613e33eec2b6776dd6fff542466db74e9ff58d 100644 --- a/source/components/stylesheet/form.mjs +++ b/source/components/stylesheet/form.mjs @@ -10,10 +10,10 @@ * For more information about purchasing a commercial license, please contact schukai GmbH. */ -import {addAttributeToken} from "../../dom/attributes.mjs"; -import {ATTRIBUTE_ERRORMESSAGE} from "../../dom/constants.mjs"; +import { addAttributeToken } from "../../dom/attributes.mjs"; +import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs"; -export {FormStyleSheet} +export { FormStyleSheet }; /** * @private @@ -22,10 +22,17 @@ export {FormStyleSheet} const FormStyleSheet = new CSSStyleSheet(); try { - FormStyleSheet.insertRule(` + FormStyleSheet.insertRule( + ` @layer form { input,meter,progress,select,textarea{accent-color:var(--monster-color-secondary-2);background-color:var(--monster-bg-color-primary-1);border-color:var(--monster-theme-control-border-color);border-radius:var(--monster-theme-control-border-radius);border-style:var(--monster-theme-control-border-style);border-width:var(--monster-theme-control-border-width);box-sizing:border-box;color:var(--monster-color-primary-1);font-family:inherit;font-size:100%;margin:0;outline:none}input,select,textarea{height:-moz-fit-content;height:fit-content;padding:.4rem .6rem}textarea{min-height:6rem;resize:vertical}input[type=color]{height:2rem;margin:0;padding:.1rem;width:2rem}input:hover:not([type=radio]):not([type=checkbox]):not([type=range]),select:hover,textarea:hover{box-shadow:var(--monster-box-shadow-2);transition:background .8s,color .25s .0833333333s}input:focus,select:focus,textarea:focus{outline:1px dashed var(--monster-color-selection-3);outline-offset:3px} -}`, 0); +}`, + 0, + ); } catch (e) { - addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + ""); + addAttributeToken( + document.getRootNode().querySelector("html"), + ATTRIBUTE_ERRORMESSAGE, + e + "", + ); } diff --git a/source/components/tree-menu/tree-menu.mjs b/source/components/tree-menu/tree-menu.mjs index d2f11304bfdc49233c024d5b8f7f02b45dba3efd..57e7c086a9879355c089ba4fffc971c4342a863b 100644 --- a/source/components/tree-menu/tree-menu.mjs +++ b/source/components/tree-menu/tree-menu.mjs @@ -12,7 +12,7 @@ * SPDX-License-Identifier: AGPL-3.0 */ -import {instanceSymbol} from "../../constants.mjs"; +import { instanceSymbol } from "../../constants.mjs"; import { buildTree } from "../../data/buildtree.mjs"; import { Datasource } from "../datatable/datasource.mjs"; import { addAttributeToken } from "../../dom/attributes.mjs"; @@ -101,7 +101,6 @@ const openEntryEventHandlerSymbol = Symbol("openEntryEventHandler"); * @fires Monster.Components.TreeMenu.event:monster-fetched */ class TreeMenu extends CustomElement { - /** * This method is called by the `instanceof` operator. * @returns {symbol} @@ -251,7 +250,7 @@ class TreeMenu extends CustomElement { if (!currentNode) { return; } - + currentNode.click(); let intend = parseInt(currentNode.getAttribute(ATTRIBUTE_INTEND)); diff --git a/source/dom/customelement.mjs b/source/dom/customelement.mjs index 07dd284e18fc9d475c1bd43679eb0a83d50961fc..5e0a1d0abf4820b7f3b6758d24488e069f9e0a3f 100644 --- a/source/dom/customelement.mjs +++ b/source/dom/customelement.mjs @@ -327,6 +327,10 @@ class CustomElement extends HTMLElement { * @property {Object} templates Specifies the templates used by the control. * @property {string} templates.main=undefined Specifies the main template used by the control. * @property {Object} templateMapping Specifies the mapping of templates. + * @property {Object} templateFormatter Specifies the formatter for the templates. + * @property {Object} templateFormatter.marker Specifies the marker for the templates. + * @property {Function} templateFormatter.marker.open=null Specifies the opening marker for the templates. + * @property {Function} templateFormatter.marker.close=null Specifies the closing marker for the templates. * @property {Boolean} eventProcessing=false Specifies whether the control processes events. * @since 1.8.0 */ @@ -339,6 +343,12 @@ class CustomElement extends HTMLElement { main: undefined, }, templateMapping: {}, + templateFormatter: { + marker: { + open: null, + close: null, + }, + }, eventProcessing: false, }; @@ -1200,7 +1210,14 @@ function initShadowRoot() { const mapping = this.getOption("templateMapping", {}); if (isObject(mapping)) { - html = new Formatter(mapping).format(html); + const formatter = new Formatter(mapping); + if (self.getOption("templateFormatter.marker.open")) { + formatter.setMarker( + self.getOption("templateFormatter.marker.open"), + self.getOption("templateFormatter.marker.close"), + ); + } + formatter.format(html); } this.shadowRoot.innerHTML = html; diff --git a/source/monster.mjs b/source/monster.mjs index 57f1e0fd53fd25627d700dfdb49788b87aaf7681..13697bb9ac653ec18ff825f99b495ef4ae5363b1 100644 --- a/source/monster.mjs +++ b/source/monster.mjs @@ -27,6 +27,7 @@ export * from "./components/layout/width-toggle.mjs"; export * from "./components/layout/panel.mjs"; export * from "./components/layout/details.mjs"; export * from "./components/layout/slider.mjs"; +export * from "./components/content/copy.mjs"; export * from "./components/form/message-state-button.mjs"; export * from "./components/form/button-bar.mjs"; export * from "./components/form/reload.mjs"; @@ -55,7 +56,7 @@ export * from "./components/form/constants.mjs"; export * from "./components/notify/message.mjs"; export * from "./components/notify/notify.mjs"; export * from "./components/notify/constants.mjs"; -//export * from "./components/tree-menu/dragable-tree-menu.mjs"; +export * from "./components/tree-menu/dragable-tree-menu.mjs"; export * from "./components/tree-menu/tree-menu.mjs"; export * from "./components/host/collapse.mjs"; export * from "./components/host/config-manager.mjs"; diff --git a/test/util/jsdom.mjs b/test/util/jsdom.mjs index f14d56a04c13bfcc21bc14ed1c3a0bd335de2d85..047b24ae0f2dec0c6e95bf842af26cbed187af84 100644 --- a/test/util/jsdom.mjs +++ b/test/util/jsdom.mjs @@ -78,8 +78,6 @@ function initJSDOM(options) { } catch(e) { console.error("Error setting key", key, e); } - - }); import("dom-storage").then(({default: Storage}) => {