UNPKG

@schukai/monster

Version:

Monster is a simple library for creating fast, robust and lightweight websites.

258 lines (225 loc) 6.77 kB
/** * 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 { assembleMethodSymbol, CustomElement, registerCustomElement, } from "../../dom/customelement.mjs"; import { findElementWithSelectorUpwards } from "../../dom/util.mjs"; import { ThemeStyleSheet } from "../stylesheet/theme.mjs"; import { Datasource } from "./datasource.mjs"; import { SpinnerStyleSheet } from "../stylesheet/spinner.mjs"; import { isString } from "../../types/is.mjs"; import { instanceSymbol } from "../../constants.mjs"; import "../form/select.mjs"; import "./datasource/dom.mjs"; import "./datasource/rest.mjs"; import "../form/popper.mjs"; import "../form/context-error.mjs"; import { StatusStyleSheet } from "./stylesheet/status.mjs"; import { Formatter } from "../../text/formatter.mjs"; export { DatasourceStatus }; /** * @private * @type {symbol} */ const errorElementSymbol = Symbol.for("errorElement"); /** * @private * @type {symbol} */ const datasourceLinkedElementSymbol = Symbol("datasourceLinkedElement"); /** * A simple dataset status component * * @fragments /fragments/components/datatable/datasource-status * * @example /examples/components/datatable/datasource-status-simple Simple dataset status * * @issue https://localhost.alvine.dev:8440/development/issues/closed/274.html * * @copyright schukai GmbH * @summary The Status component is used to show the current status of a datasource. */ class DatasourceStatus extends CustomElement { /** */ constructor() { super(); } /** * This method is called by the `instanceof` operator. * @return {symbol} */ static get [instanceSymbol]() { return Symbol.for("@schukai/monster/components/datatable/status@@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} datasource Datasource configuration * @property {string} datasource.selector The selector of the datasource * @property {Object} callbacks Callbacks * @property {Function} callbacks.onError Callback function for error handling <code>function(message: string, event: Event): string</code> * @property {Object} timeouts Timeouts * @property {number} timeouts.message Timeout for the message * @property {Object} state State */ get defaults() { return Object.assign({}, super.defaults, { templates: { main: getTemplate(), }, datasource: { selector: null, }, callbacks: { onError: null, }, timeouts: { message: 4000, }, state: { spinner: "hide", }, }); } /** * * @return {string} */ static getTag() { return "monster-datasource-status"; } /** * @private */ [assembleMethodSymbol]() { super[assembleMethodSymbol](); initControlReferences.call(this); initEventHandler.call(this); } /** * * @param message * @param timeout * @returns {DatasourceStatus} */ setErrorMessage(message, timeout) { this[errorElementSymbol].setErrorMessage(message, timeout); return this; } /** * * @return [CSSStyleSheet] */ static getCSSStyleSheet() { return [StatusStyleSheet, SpinnerStyleSheet, ThemeStyleSheet]; } } /** * @private * @return {Select} * @throws {Error} no shadow-root is defined */ function initControlReferences() { if (!this.shadowRoot) { throw new Error("no shadow-root is defined"); } this[errorElementSymbol] = this.shadowRoot.querySelector( "monster-context-error", ); } /** * @private */ function initEventHandler() { const selector = this.getOption("datasource.selector", ""); const self = this; if (isString(selector)) { const element = findElementWithSelectorUpwards(this, selector); if (element === null) { throw new Error("the selector must match exactly one element"); } if (!(element instanceof Datasource)) { throw new TypeError("the element must be a datasource"); } let fadeOutTimer = null; this[datasourceLinkedElementSymbol] = element; element.addEventListener("monster-datasource-fetched", function () { fadeOutTimer = setTimeout(() => { self.setOption("state.spinner", "hide"); }, 800); }); element.addEventListener("monster-datasource-fetch", function () { if (fadeOutTimer) { clearTimeout(fadeOutTimer); fadeOutTimer = null; } self.setOption("state.spinner", "show"); }); element.addEventListener("monster-datasource-error", function (event) { if (fadeOutTimer) { clearTimeout(fadeOutTimer); fadeOutTimer = null; } self.setOption("state.spinner", "hide"); const timeout = self.getOption("timeouts.message", 4000); let msg = "Cannot load data"; try { if (event.detail.error instanceof Error) { msg = event.detail.error.message; } else if (event.detail.error instanceof Object) { msg = JSON.stringify(event.detail.error); } else if (event.detail.error instanceof String) { msg = event.detail.error; } else if (event.detail.error instanceof Number) { msg = event.detail.error.toString(); } else { msg = event.detail.error; } } catch (e) { } finally { const callback = self.getOption("callbacks.onError", null); if (callback) { callback.call(self, msg, event); } else { self[errorElementSymbol].setErrorMessage(msg, timeout); } } }); } } /** * @private * @return {string} */ function getTemplate() { // language=HTML return ` <div data-monster-role="control" part="control" data-monster-attributes="disabled path:disabled | if:true"> <monster-context-error data-monster-option-classes-button="monster-theme-error-2 monster-theme-background-inherit"></monster-context-error> <div class="monster-spinner" data-monster-attributes="data-monster-state-loader path:state.spinner"></div> </div> `; } registerCustomElement(DatasourceStatus);