import { UiElement } from "../UiElement.js";
import "./Sidebar.css";
export { Sidebar };
/**
* Sidebar with content group navigation
*
* @author rhess <robin.hess@awi.de>
* @memberof vef.ui.sidebar
*/
class Sidebar extends UiElement {
classes = ["sidebar", "collapsed"];
html = `
<div class="sidebar-menu"></div>
<div class="sidebar-content">
<div class="sidebar-header">
<div class="sidebar-title"></div>
<i class="fas fa-times"></i>
</div>
</div>
`;
/**
* Create sidebar and optionally append it to a target element.
* {@code target} can be an "#id" with a hash in the beginning
* or an instance of HTMLElement.
*
* @param {string/HTMLElement} target id or HTMLElement (optional)
*/
constructor(target, options) {
super(target, {
"show": [],
"close": []
});
this.groups_ = {};
this.activeGroup_ = null;
this.setHtml(this.html);
this.setClass(this.classes);
this.query(".fas.fa-times").addEventListener("click", () => this.close());
// set options with defaults
this.setOptions(Object.assign({
position: "left",
menu: true,
closeable: true,
responsive: true,
underlineHeader: false
}, options));
}
setOptions(options) {
// positioning of the sidebar
if (options.position == "left") {
this.removeClass(["right", "bottom"]);
this.setClass("left");
} else if (options.position == "right") {
this.removeClass(["left", "bottom"]);
this.setClass("right");
} else if (options.position == "bottom") {
this.removeClass(["left", "right"]);
this.setClass("bottom");
}
// responsive or fixed size
if (typeof options.menu == "boolean") {
if (options.menu) {
this.setClass("menu");
} else {
this.removeClass("menu");
}
}
// underline headline
if (typeof options.underlineHeader == "boolean") {
if (options.underlineHeader) {
this.setClass("underline-header");
} else {
this.removeClass("underline-header");
}
}
// show close button ?
if (typeof options.closeable == "boolean") {
if (options.closeable) {
this.setClass("closeable");
} else {
this.removeClass("closeable");
}
}
// show close button ?
if (typeof options.responsive == "boolean") {
if (options.responsive) {
this.setClass("responsive");
} else {
this.removeClass("responsive");
}
}
}
/**
* Adds a content group in the sidebar navigation
*
* @param {string} name identifier of the group
* @param {string} title headline of the group
* @param {string} classNames css classes separated by space
* @param {string/HTMLElement} content content as HTML-String or HTMLElement
* @param {string} position "begin" or "end" (default is end)
*/
addGroup(name, title, classNames, content, position = "end") {
if (!this.groups_[name]) {
const menuElement = document.createElement("div");
menuElement.classList.add("menu-element");
menuElement.setAttribute("tabindex", "0");
if (classNames) {
const classes = classNames.trim().split(" ");
for (let i in classes) {
menuElement.classList.add(classes[i]);
}
}
menuElement.addEventListener("click", e => {
if (this.activeGroup_ == this.groups_[name]) {
this.close();
} else {
this.show(name);
}
}, false);
menuElement.addEventListener("keydown", e => {
if(e.key != "Enter") return;
if (this.activeGroup_ == this.groups_[name]) {
this.close();
} else {
this.show(name);
}
}, false);
const contentContainer = document.createElement("div");
contentContainer.classList.add("sidebar-group");
contentContainer.dataset.title = title;
if (content && typeof content == "string") {
contentContainer.insertAdjacentHTML('afterbegin', content);
} else if (content instanceof HTMLElement) {
contentContainer.appendChild(content);
}
this.query(".sidebar-menu").insertAdjacentElement((position == "begin") ? "afterbegin" : "beforeend", menuElement);
this.query(".sidebar-content").appendChild(contentContainer);
this.groups_[name] = {
menuElement: menuElement,
content: contentContainer,
title: title
};
}
}
/**
* Update the title of a group wth the given name
*
* @param {string} name
* @param {string} title
*/
setTitle(name, title) {
if (this.groups_[name] && (typeof title == "string")) {
this.groups_[name].title = title;
this.groups_[name].content.dataset.title = title;
if (this.activeGroup_ == this.groups_[name]) {
const titleContainer = this.getElement().querySelector(".sidebar-header .sidebar-title");
titleContainer.innerHTML = title;
titleContainer.title = titleContainer.innerText;
}
}
}
/**
* Update the content of a group with the given name
*
* @param {string} name
* @param {string | HTMLElement} content
* @param {boolean} keepScrollposition
*/
setContent(name, content, keepScrollposition) {
const group = this.groups_[name];
if (group) {
if (!keepScrollposition) group.content.scrollTo(0, 0);
if (typeof content == "string") {
group.content.innerHTML = content;
} else if (content instanceof HTMLElement) {
group.content.innerHTML = "";
group.content.appendChild(content);
} else {
group.content.innerHTML = "";
}
}
}
/**
* Remove content group from the sidebar navigation
*
* @param {string} name identifier of the group
*/
removeGroup(name) {
if (this.groups_[name]) {
if (this.groups_[name] == this.activeGroup_) this.close();
this.groups_[name].menuElement.remove();
this.groups_[name].content.remove();
delete this.groups_[name];
}
}
/**
* Returns all defined groups.
*/
getGroups() {
return this.groups_;
}
/**
* Show the content of a group
*
* @param {string} name identifier of the group
*/
show(name) {
if (this.groups_[name]) {
if (this.activeGroup_) {
this.activeGroup_.menuElement.classList.remove("active");
this.activeGroup_.content.classList.remove("show");
}
this.removeClass("collapsed");
const titleContainer = this.getElement().querySelector(".sidebar-header .sidebar-title");
titleContainer.innerHTML = (this.groups_[name].title) ? this.groups_[name].title : "";
titleContainer.title = titleContainer.innerText;
this.groups_[name].menuElement.classList.add("active");
this.groups_[name].content.classList.add("show");
this.groups_[name].content.scrollTo(0, 0);
this.activeGroup_ = this.groups_[name];
this.fire("show", name);
} else {
this.close();
}
}
/**
* Close the sidebar
*/
close() {
this.setClass("collapsed");
if (this.activeGroup_) {
this.activeGroup_.menuElement.classList.remove("active");
this.activeGroup_.content.classList.remove("show");
this.activeGroup_ = null;
}
this.fire("close");
}
/**
* get container element of a content group
*
* @param {string} name identifier of the group
* @returns {HTMLElement} content container
*/
getGroupContainer(name) {
if (this.groups_[name]) {
return this.groups_[name].content;
}
}
isOpen() {
return !this.getElement().classList.contains("collapsed");
}
}