Skip to content
Snippets Groups Projects
Select Git revision
  • ce1dd137678aaee721c92dd3cfdf88a52001f9af
  • master default protected
  • 1.31
  • 4.38.2
  • 4.38.1
  • 4.38.0
  • 4.37.2
  • 4.37.1
  • 4.37.0
  • 4.36.0
  • 4.35.0
  • 4.34.1
  • 4.34.0
  • 4.33.1
  • 4.33.0
  • 4.32.2
  • 4.32.1
  • 4.32.0
  • 4.31.0
  • 4.30.1
  • 4.30.0
  • 4.29.1
  • 4.29.0
23 results

change-button.mjs

Blame
  • change-button.mjs 8.56 KiB
    /**
     * 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 { addAttributeToken } from "../../dom/attributes.mjs";
    import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs";
    import {
    	assembleMethodSymbol,
    	CustomElement,
    	registerCustomElement,
    } from "../../dom/customelement.mjs";
    import { isString } from "../../types/is.mjs";
    import { State } from "../form/types/state.mjs";
    import "../form/state-button.mjs";
    import { ATTRIBUTE_DATASOURCE_SELECTOR } from "./constants.mjs";
    import { ChangeButtonStyleSheet } from "./stylesheet/change-button.mjs";
    
    export { ChangeButton };
    
    /**
     * @private
     * @type {symbol}
     */
    const stateButtonElementSymbol = Symbol("stateButtonElement");
    
    /**
     * @private
     * @type {symbol}
     */
    const datasetLinkedElementSymbol = Symbol("datasetLinkedElement");
    /**
     * @private
     * @type {symbol}
     */
    const overlayLinkedElementSymbol = Symbol("overlayLinkedElement");
    
    /**
     * The ColumnBar component is used to show and configure the columns of a datatable.
     *
     * <img src="./images/change-button.png">
     *
     * You can create this control either by specifying the HTML tag <monster-datatable-change-button />` directly in the HTML or using
     * Javascript via the `document.createElement('monster-datatable-change-button');` method.
     *
     * ```html
     * <monster-datatable-change-button></monster-datatable-change-button>
     * ```
     *
     * Or you can create this CustomControl directly in Javascript:
     *
     * ```js
     * import '@schukai/monster/components/datatable/change-button.mjs';
     * document.createElement('monster-datatable-change-button');
     * ```
     *
     * The Body should have a class "hidden" to ensure that the
     * styles are applied correctly.
     *
     * ```css
     * body.hidden {
     *    visibility: hidden;
     * }
     * ```
     *
     * @startuml change-button.png
     * skinparam monochrome true
     * skinparam shadowing false
     * HTMLElement <|-- CustomElement
     * CustomElement <|-- ChangeButton
     * @enduml
     *
     * @copyright schukai GmbH
     * @memberOf Monster.Components.Datatable
     * @summary A data set
     */
    class ChangeButton extends CustomElement {
    	/**
    	 * This method is called by the `instanceof` operator.
    	 * @returns {symbol}
    	 */
    	static get [instanceSymbol]() {
    		return Symbol.for(
    			"@schukai/monster/components/datasource/change-button@@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 The datasource
    	 * @property {string} datasource.selector The selector of the datasource
    	 * @property {object} mapping The mapping
    	 * @property {string} mapping.data The data
    	 * @property {number} mapping.index The index
    	 * @property {Array} data The data
    	 * @return {Object}
    	 */
    	get defaults() {
    		const obj = Object.assign({}, super.defaults, {
    			templates: {
    				main: getTemplate(),
    			},
    
    			labels: {
    				button: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"
                                 class="bi bi-grid" viewBox="0 0 16 16">
                                <path d="M1 2.5A1.5 1.5 0 0 1 2.5 1h3A1.5 1.5 0 0 1 7 2.5v3A1.5 1.5 0 0 1 5.5 7h-3A1.5 1.5 0 0 1 1 5.5zM2.5 2a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5zm6.5.5A1.5 1.5 0 0 1 10.5 1h3A1.5 1.5 0 0 1 15 2.5v3A1.5 1.5 0 0 1 13.5 7h-3A1.5 1.5 0 0 1 9 5.5zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5zM1 10.5A1.5 1.5 0 0 1 2.5 9h3A1.5 1.5 0 0 1 7 10.5v3A1.5 1.5 0 0 1 5.5 15h-3A1.5 1.5 0 0 1 1 13.5zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5zm6.5.5A1.5 1.5 0 0 1 10.5 9h3a1.5 1.5 0 0 1 1.5 1.5v3a1.5 1.5 0 0 1-1.5 1.5h-3A1.5 1.5 0 0 1 9 13.5zm1.5-.5a.5.5 0 0 0-.5.5v3a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-3a.5.5 0 0 0-.5-.5z"/>
                            </svg>`,
    			},
    
    			classes: {
    				bar: "monster-button-primary",
    			},
    
    			dataset: {
    				selector: null,
    			},
    
    			overlay: {
    				selector: null,
    			},
    
    			mapping: {
    				data: "dataset",
    				index: 0,
    			},
    
    			data: {},
    
    			disabled: false,
    		});
    
    		updateOptionsFromArguments.call(this, obj);
    		return obj;
    	}
    
    	/**
    	 *
    	 * @return {string}
    	 */
    	static getTag() {
    		return "monster-datatable-change-button";
    	}
    
    	/**
    	 * This method is responsible for assembling the component.
    	 */
    	[assembleMethodSymbol]() {
    		super[assembleMethodSymbol]();
    
    		initControlReferences.call(this);
    		initEventHandler.call(this);
    	}
    
    	/**
    	 *
    	 * @return [CSSStyleSheet]
    	 */
    	static getCSSStyleSheet() {
    		return [ChangeButtonStyleSheet];
    	}
    }
    
    /**
     * @private
     * @return {Monster.Components.Datatable.Form}
     */
    function initControlReferences() {
    	if (!this.shadowRoot) {
    		throw new Error("no shadow-root is defined");
    	}
    
    	const selector = this.getOption("dataset.selector");
    
    	if (isString(selector)) {
    		const elements = document.querySelectorAll(selector);
    		if (elements.length !== 1) {
    			throw new Error("the selector must match exactly one element");
    		}
    
    		const element = elements[0];
    		if (!(element instanceof HTMLElement)) {
    			throw new TypeError("the element must be a dataset");
    		}
    
    		this[datasetLinkedElementSymbol] = element;
    	}
    
    	const selector2 = this.getOption("overlay.selector");
    
    	if (isString(selector2)) {
    		const elements = document.querySelectorAll(selector2);
    		if (elements.length !== 1) {
    			throw new Error("the selector must match exactly one element");
    		}
    
    		const element = elements[0];
    		if (!(element instanceof HTMLElement)) {
    			throw new TypeError("the element must be a overlay");
    		}
    
    		this[overlayLinkedElementSymbol] = element;
    	}
    
    	this[stateButtonElementSymbol] = this.shadowRoot.querySelector(
    		"[data-monster-role=state-button]",
    	);
    
    	if (this[stateButtonElementSymbol]) {
    		setTimeout(() => {
    			const states = {
    				changed: new State(
    					"changed",
    					`<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-record-circle" viewBox="0 0 16 16">
                                      <path 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 d="M11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0"/>
                                   </svg>`,
    				),
    			};
    
    			this[stateButtonElementSymbol].removeState();
    			this[stateButtonElementSymbol].setOption("states", states);
    			this[stateButtonElementSymbol].setOption(
    				"labels.button",
    				this.getOption("labels.button"),
    			);
    		}, 1);
    	}
    
    	return this;
    }
    
    function getIndex() {
    	if (!(this instanceof HTMLElement)) {
    		return;
    	}
    
    	const row = this.closest("[data-monster-insert-reference]");
    	if (!row) {
    		addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, "no reference found");
    		return;
    	}
    
    	const ref = row.getAttribute("data-monster-insert-reference");
    	if (!ref) {
    		addAttributeToken(
    			this,
    			ATTRIBUTE_ERRORMESSAGE,
    			"reference is missing or empty",
    		);
    		return;
    	}
    
    	const index = Number(ref.split("-").pop());
    	if (isNaN(index)) {
    		return;
    	}
    
    	return index;
    }
    
    /**
     * @private
     */
    function initEventHandler() {
    	setTimeout(() => {
    		this[stateButtonElementSymbol].setOption("actions.click", () => {
    			const index = getIndex.call(this);
    
    			if (!isNaN(index)) {
    				this[datasetLinkedElementSymbol].setOption("mapping.index", index);
    				this[overlayLinkedElementSymbol].open();
    			}
    		});
    	}, 1);
    }
    
    /**
     * @param {Object} options
     */
    function updateOptionsFromArguments(options) {
    	const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
    	if (selector) {
    		options.datasource.selector = selector;
    	}
    }
    
    /**
     * @private
     * @return {string}
     */
    function getTemplate() {
    	// language=HTML
    	return `
            <div data-monster-role="control" part="control"
                 data-monster-attributes="disabled path:disabled | if:true">
                <monster-state-button data-monster-role="state-button"></monster-state-button>
    
            </div>
        `;
    }
    
    registerCustomElement(ChangeButton);