Source: ui/UiElement.js

import { EventObject } from "../events/EventObject.js";
import "./UiElement.css";

export { UiElement };

/**
 * Base class for Ui Elements. Creates a container and can be added to the DOM
 * 
 * @author rhess <robin.hess@awi.de>
 * @memberof vef.ui
 */
class UiElement extends EventObject {

    /**
     * Create the element and optionally append it to a target element.
     * {@code target} can be an "#id" with or without a hash in the beginning
     * or an instance of HTMLElement. Creates a <div>-Element as a container
     * inside {@code this.element_}
     * 
     * @param {string/HTMLElement} target id or HTMLElement (optional)
     * @param {Object} events events for the EventObject (optional)
     * @param {string | HTMLElement} position (optional, default=beforeend) beforebegin, afterbegin, beforeend, afterend
     */
    constructor(target, events, position) {
        super(events);

        this.events["append"] = [];
        this.element_ = document.createElement("div");
        this.element_.classList.add("vef-ui");

        if (target) this.appendTo(target, position);
    }

    /**
     * @private
     */
    setClass_(className) {
        if ((typeof className == "string") && (className.length > 0)) this.element_.classList.add(className);
    }

    /**
     * Set the classnames of the main element
     * @param {string[]} classes 
     */
    setClass(classes) {
        if (Array.isArray(classes)) {
            classes.forEach(className => this.setClass_(className));
        } else {
            this.setClass_(classes)
        }
    }

    /**
     * @private
     */
    removeClass_(className) {
        if ((typeof className == "string") && (className.length > 0)) this.element_.classList.remove(className);
    }

    /**
     * Remove the classnames from the main element
     * @param {string[]} classes 
     */
    removeClass(classes) {
        if (Array.isArray(classes)) {
            classes.forEach(className => this.removeClass_(className));
        } else {
            this.removeClass_(classes)
        }
    }

    /**
     * Set the innerHTML content of the main element
     * @param {string} html 
     */
    setHtml(html) {
        this.element_.innerHTML = (typeof html == "string") ? html : "";
    }

    /**
     * Append the sidebar to a target element.
     * {@code target} can be an "#id" with with or without a hash in the beginning
     * or an instance of HTMLElement.
     * 
     * @param {string | HTMLElement} target id or HTMLElement
     * @param {string | HTMLElement} position (optional, default=beforeend) beforebegin, afterbegin, beforeend, afterend
     */
    appendTo(target, position) {
        if (!["beforebegin", "afterbegin", "beforeend", "afterend"].includes(position)) {
            position = "beforeend";
        }
        if ((typeof target == "string")) {
            if (!target.startsWith("#")) target = "#" + target;
            const container = document.querySelector(target);
            container.insertAdjacentElement(position, this.element_);
            this.fire("append", { target: target, element: this });
        } else if (target instanceof HTMLElement) {
            target.appendChild(this.element_);
            target.insertAdjacentElement(position, this.element_);
            this.fire("append", { target: target, element: this });
        }
    }

    /**
     * scroll the parent to this elements location
     */
    scroll() {
        const parent = this.element_.parentElement;

        if (parent) {
            parent.scrollTo({
                top: this.element_.offsetTop - parent.offsetTop,
                left: this.element_.offsetLeft - parent.offsetLeft,
                behavior: 'smooth'
            });
        }
    }

    /**
     * Apply a querySelector on the element
     * @param {string} selector 
     */
    query(selector) {
        return this.element_.querySelector(selector);
    }

    /**
     * Apply a querySelectorAll on the element
     * @param {string} selector 
     */
    queryAll(selector) {
        return this.element_.querySelectorAll(selector);
    }

    /**
     * Get the Ui Element container
     * 
     * @returns {HTMLElement} element
     */
    getElement() {
        return this.element_;
    }

    /**
     * Remove the UiElement from the DOM and clean
     * up the memory if necessary for garbage collection
     * 
     * override this method if further cleanup is required.
     */
    dispose() {
        this.element_.remove();
    }

}