Skip to content
Snippets Groups Projects
Select Git revision
  • 71703e6145bf2daf87208e71dadc4313a7fc6fce
  • master default protected
  • 1.31
  • 4.25.2
  • 4.25.1
  • 4.25.0
  • 4.24.3
  • 4.24.2
  • 4.24.1
  • 4.24.0
  • 4.23.6
  • 4.23.5
  • 4.23.4
  • 4.23.3
  • 4.23.2
  • 4.23.1
  • 4.23.0
  • 4.22.3
  • 4.22.2
  • 4.22.1
  • 4.22.0
  • 4.21.0
  • 4.20.1
23 results

Monster_Constraints.OrOperator.html

Blame
  • columnbar.mjs 7.50 KiB
    /**
     * Copyright 2023 schukai GmbH
     * SPDX-License-Identifier: AGPL-3.0
     */
    
    import { instanceSymbol } from "../../constants.mjs";
    import {
    	assembleMethodSymbol,
    	CustomElement,
    	registerCustomElement,
    } from "../../dom/customelement.mjs";
    import { findTargetElementFromEvent } from "../../dom/events.mjs";
    import { clone } from "../../util/clone.mjs";
    import { ColumnBarStyleSheet } from "./stylesheet/column-bar.mjs";
    import { createPopper } from "@popperjs/core";
    
    export { ColumnBar };
    
    /**
     * @private
     * @type {symbol}
     */
    const settingsButtonElementSymbol = Symbol("settingButtonElement");
    
    /**
     * @private
     * @type {symbol}
     */
    const settingsButtonEventHandlerSymbol = Symbol("settingsButtonEventHandler");
    
    /**
     * @private
     * @type {symbol}
     */
    const settingsLayerElementSymbol = Symbol("settingsLayerElement");
    
    /**
     * @private
     * @type {symbol}
     */
    const dotsContainerElementSymbol = Symbol("dotsContainerElement");
    
    /**
     * @private
     * @type {symbol}
     */
    const popperInstanceSymbol = Symbol("popperInstance");
    
    /**
     * The ColumnBar component is used to show and configure the columns of a datatable.
     *
     * <img src="./images/column-bar.png">
     *
     * You can create this control either by specifying the HTML tag <monster-column-bar />` directly in the HTML or using
     * Javascript via the `document.createElement('monster-column-bar');` method.
     *
     * ```html
     * <monster-column-bar></monster-column-bar>
     * ```
     *
     * Or you can create this CustomControl directly in Javascript:
     *
     * ```js
     * import '@schukai/monster/components/datatable/column-bar.mjs';
     * document.createElement('monster-column-bar');
     * ```
     *
     * The Body should have a class "hidden" to ensure that the styles are applied correctly.
     *
     * ```css
     * body.hidden {
     *    visibility: hidden;
     * }
     * ```
     *
     * @startuml column-bar.png
     * skinparam monochrome true
     * skinparam shadowing false
     * HTMLElement <|-- CustomElement
     * CustomElement <|-- ColumnBar
     * @enduml
     *
     * @copyright schukai GmbH
     * @memberOf Monster.Components.Datatable
     * @summary A data set
     */
    class ColumnBar extends CustomElement {
    	/**
    	 * This method is called by the `instanceof` operator.
    	 * @returns {symbol}
    	 */
    	static get [instanceSymbol]() {
    		return Symbol.for("@schukai/monster/components/column-bar");
    	}
    
    	/**
    	 * 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 {boolean} autoLoad If true, the datasource is called immediately after the control is created.
    	 */
    	get defaults() {
    		const obj = Object.assign({}, super.defaults, {
    			templates: {
    				main: getTemplate(),
    			},
    			locale: {
    				settings: "Settings",
    			},
    
    			columns: [],
    		});
    
    		return obj;
    	}
    
    	/**
    	 *
    	 * @return {string}
    	 */
    	static getTag() {
    		return "monster-column-bar";
    	}
    
    	/**
    	 *
    	 * @return {Monster.Components.Form.Form}
    	 */
    	[assembleMethodSymbol]() {
    		super[assembleMethodSymbol]();
    
    		initControlReferences.call(this);
    		initEventHandler.call(this);
    	}
    
    	/**
    	 * @return {Array<ColumnBarStyleSheet>}
    	 */
    	static getCSSStyleSheet() {
    		return [ColumnBarStyleSheet];
    	}
    }
    
    /**
     * @private
     * @return {Monster.Components.Datatable.Form}
     */
    function initControlReferences() {
    	if (!this.shadowRoot) {
    		throw new Error("no shadow-root is defined");
    	}
    
    	this[settingsButtonElementSymbol] = this.shadowRoot.querySelector(
    		"[data-monster-role=settings-button]",
    	);
    	this[settingsLayerElementSymbol] = this.shadowRoot.querySelector(
    		"[data-monster-role=settings-layer]",
    	);
    	this[dotsContainerElementSymbol] = this.shadowRoot.querySelector(
    		"[data-monster-role=dots]",
    	);
    	return this;
    }
    
    /**
     * @private
     */
    function initEventHandler() {
    	const self = this;
    
    	self[popperInstanceSymbol] = createPopper(
    		self[settingsButtonElementSymbol],
    		self[settingsLayerElementSymbol],
    		{
    			placement: "auto",
    
    			modifiers: [
    				{
    					name: "offset",
    					options: {
    						offset: [10, 10],
    					},
    				},
    			],
    		},
    	);
    
    	self[dotsContainerElementSymbol].addEventListener("click", function (event) {
    		const element = findTargetElementFromEvent(
    			event,
    			"data-monster-role",
    			"column",
    		);
    		if (element) {
    			const index = element.getAttribute("data-monster-index");
    			event.preventDefault();
    
    			const columns = clone(self.getOption("columns"));
    
    			const column = columns.find((col) => {
    				return parseInt(col.index) === parseInt(index);
    			});
    
    			column.visible = !column.visible;
    			self.setOption("columns", columns);
    		}
    	});
    
    	self[settingsButtonEventHandlerSymbol] = (event) => {
    		const clickTarget = event.composedPath()?.[0];
    		if (
    			self[settingsLayerElementSymbol] === clickTarget ||
    			self[settingsLayerElementSymbol].contains(clickTarget)
    		) {
    			return;
    		}
    		self[settingsLayerElementSymbol].classList.remove("visible");
    		document.body.removeEventListener(
    			"click",
    			self[settingsButtonEventHandlerSymbol],
    		);
    	};
    
    	self[settingsButtonElementSymbol].addEventListener("click", function (event) {
    		const element = findTargetElementFromEvent(
    			event,
    			"data-monster-role",
    			"settings-button",
    		);
    
    		if (element) {
    			self[settingsLayerElementSymbol].classList.toggle("visible");
    			event.preventDefault();
    
    			if (self[settingsLayerElementSymbol].classList.contains("visible")) {
    				self[popperInstanceSymbol].update();
    
    				setTimeout(() => {
    					document.body.addEventListener(
    						"click",
    						self[settingsButtonEventHandlerSymbol],
    					);
    				}, 0);
    			}
    		}
    	});
    
    	self[settingsLayerElementSymbol].addEventListener("change", function (event) {
    		const control = event.target;
    		const index = control.getAttribute("data-monster-index");
    
    		const columns = clone(self.getOption("columns"));
    
    		const column = columns.find((col) => {
    			return parseInt(col.index) === parseInt(index);
    		});
    
    		column.visible = control.checked;
    		self.setOption("columns", columns);
    	});
    }
    
    /**
     * @private
     * @return {string}
     */
    function getTemplate() {
    	// language=HTML
    	return `
            <template id="column">
                <div data-monster-role="column">
                    <label><input type="checkbox" data-monster-attributes="
                    data-monster-index path:column.index,
                    checked path:column.visible | ?:checked:"><span
                    data-monster-replace="path:column.name"
                    ></span></label>
                </div>
            </template>
            <template id="dots">
                <li data-monster-insert="">
                    <a href="#" data-monster-role="column"
                       data-monster-attributes="
                       class path:dots.visible | ?:is-hidden:is-visible,
                       title path:dots.name,
                         data-monster-index path:dots.index">
                    </a>
                </li>
            </template>
    
            <div data-monster-role="control" part="control" data-monster-select-this="true" data-monster-attributes="class path:columns | has-entries | ?::hidden">
                <ul data-monster-insert="dots path:columns" 
                    data-monster-role="dots"></ul>
                <a href="#" data-monster-role="settings-button" data-monster-replace="path:locale.settings">Settings</a>
                <div data-monster-role="settings-layer">
                    <div data-monster-insert="column path:columns" data-monster-role="settings-popup-list">
                    </div>
                </div>
            </div>
        `;
    }
    
    registerCustomElement(ColumnBar);