/** * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved. * Node module: @schukai/monster * * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3). * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html * * For those who do not wish to adhere to the AGPLv3, a commercial license is available. * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms. * For more information about purchasing a commercial license, please contact schukai GmbH. * * SPDX-License-Identifier: AGPL-3.0 */ import { instanceSymbol } from "../../constants.mjs"; import { assembleMethodSymbol, registerCustomElement, } from "../../dom/customelement.mjs"; import { ContextErrorStyleSheet } from "./stylesheet/context-error.mjs"; import { ThemeStyleSheet } from "../stylesheet/theme.mjs"; import { Popper } from "../layout/popper.mjs"; import { ATTRIBUTE_ERRORMESSAGE, ATTRIBUTE_ROLE, } from "../../dom/constants.mjs"; export { ContextError }; /** * @private * @type {symbol} */ const controlElementSymbol = Symbol("controlElement"); /** * @private * @type {symbol} */ const buttonElementSymbol = Symbol("buttonElement"); /** * local symbol * @private * @type {symbol} */ const popperElementSymbol = Symbol("popperElement"); /** * local symbol * @private * @type {symbol} */ const iconElementSymbol = Symbol("iconElement"); /** * The ContextError control shows an error message in a popper. * * @fragments /fragments/components/form/context-error/ * * @example /examples/components/form/context-error-simple * * @copyright schukai GmbH * @memberOf Monster.Components.Form * @summary A control that can be used to display a tooltip or a popover with an error message. **/ /** * A context error control. * * @fragments /fragments/components/form/select/ * * @example /examples/components/form/select-simple * * @since 3.55.0 * @copyright schukai GmbH * @summary A context error control */ class ContextError extends Popper { /** * This method is called by the `instanceof` operator. * * @returns {symbol} */ static get [instanceSymbol]() { return Symbol.for( "@schukai/monster/components/form/context-error@@instance", ); } /** * * @return {void} */ [assembleMethodSymbol]() { super[assembleMethodSymbol](); initControlReferences.call(this); setTimeout(() => { if (this.hasErrorMessage()) { this[iconElementSymbol].classList.remove("hidden"); } }, 1000); } /** * 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 The templates for the control. * @property {string} templates.main The main template. * @property {string} mode The mode of the popper. Possible values are `click`, `enter` and `hover`. * @property {string} content The content of the popper. * @property {object} popper The popper options. * @property {string} popper.placement The placement of the popper. Possible values are `top`, `bottom`, `left`, `right`, `auto`, `auto-start`, `auto-end`, `top-start`, `top-end`, `bottom-start`, `bottom-end`, `right-start`, `right-end`, `left-start`, `left-end`. */ get defaults() { return Object.assign({}, super.defaults, { templates: { main: getTemplate(), }, mode: "auto", content: "<slot></slot>", classes: { button: "monster-theme-error-2", }, }); } /** * * @return {ContextError} */ showDialog() { if (!this.hasErrorMessage()) { return this; } super.showDialog(); return this; } /** * * @return {ContextError} */ hideDialog() { super.hideDialog(); return this; } /** * * @param message * @param show {boolean|number|string} - If true the dialog is shown immediately. If false the dialog is hidden by default. If a number is specified the dialog is shown for the specified time in milliseconds. * @returns {ContextError} */ setErrorMessage(message, show = false) { message = message.trim(); if (message === "") { return this.resetErrorMessage(); } this.setOption("content", message); this[iconElementSymbol].classList.remove("hidden"); if (show === true || show === 1 || show === "true") { this.showDialog(); return this; } if (show === false || show === 0 || show === "false") { return this; } try { const interval = parseInt(show); this.showDialog(); setTimeout(() => { this.hideDialog(); }, interval); } catch (e) {} return this; } /** * Reset the error message. * @returns {ContextError} */ resetErrorMessage() { this.hideDialog(); this.setOption("content", ""); this[iconElementSymbol].classList.add("hidden"); return this; } /** * Returns true if an error message is set. * @returns {boolean} */ hasErrorMessage() { const c = this.getOption("content"); if (c === "") { return false; } if (c === "<slot></slot>") { const sr = this.shadowRoot; if (!sr) { return false; } const slot = sr.querySelector("slot"); if (!slot) { return false; } return this.shadowRoot.querySelector("slot").assignedNodes().length > 0; } return true; } /** * Returns the html tag of the control. * * @return {string} */ static getTag() { return "monster-context-error"; } /** * @return {CSSStyleSheet[]} */ static getCSSStyleSheet() { return [ContextErrorStyleSheet, ThemeStyleSheet]; } } /** * @private * @return {Select} */ function initControlReferences() { this[controlElementSymbol] = this.shadowRoot.querySelector( `[${ATTRIBUTE_ROLE}=control]`, ); this[buttonElementSymbol] = this.shadowRoot.querySelector( `[${ATTRIBUTE_ROLE}=button]`, ); this[popperElementSymbol] = this.shadowRoot.querySelector( `[${ATTRIBUTE_ROLE}=popper]`, ); this[iconElementSymbol] = this.shadowRoot.querySelector( "[data-monster-role=button] svg", ); } /** * @private * @return {string} */ function getTemplate() { // language=HTML return ` <div data-monster-role="control" part="control"> <div data-monster-role="button" data-monster-attributes="class path:classes.button" part="button"> <svg xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" class="hidden" viewBox="0 0 16 16"> <path fill="var(--monster-color-error-2)" d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/> <path fill="var(--monster-color-error-2)" d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0z"/> </svg> </div> <div data-monster-role="popper" part="popper" tabindex="-1" class="monster-color-primary-1"> <div data-monster-role="arrow"></div> <div part="content" class="flex"> <div data-monster-replace="path:content"></div> </div> </div> </div> `; } registerCustomElement(ContextError);