109 lines
3.6 KiB
JavaScript
109 lines
3.6 KiB
JavaScript
import { positionAsTooltip } from "./tooltip.js";
|
|
import { registerLoadCallback } from "./main.js";
|
|
|
|
let activeMenuBar = null;
|
|
|
|
registerLoadCallback(() => {
|
|
document.querySelectorAll(".menu-bar").forEach(menuBar => {
|
|
menuBar.querySelectorAll("button").forEach(button => {
|
|
button.setAttribute("tabindex", "-1");
|
|
button.replaceChildren(createAltSpan(button, button.innerText));
|
|
button.addEventListener("click", e => {
|
|
menuBar.classList.remove("active");
|
|
menuBar.querySelectorAll(".active")
|
|
.forEach(elem => elem.classList.remove("active"));
|
|
activeMenuBar = null;
|
|
});
|
|
button.addEventListener("mouseenter", () => {
|
|
if (!activeMenuBar) return;
|
|
|
|
button.parentElement.querySelectorAll(".active")
|
|
.forEach(elem => elem.classList.remove("active"));
|
|
});
|
|
});
|
|
menuBar.querySelectorAll("[data-section]").forEach(section => {
|
|
const button = document.createElement("button");
|
|
button.setAttribute("tabindex", "-1");
|
|
button.dataset.forSection = "";
|
|
button.appendChild(createAltSpan(section, section.dataset.section));
|
|
section.parentElement.insertBefore(button, section);
|
|
|
|
section.addEventListener("click", e => e.stopPropagation());
|
|
button.addEventListener("click", e => e.stopPropagation());
|
|
|
|
function updateActive() {
|
|
if (!activeMenuBar) return;
|
|
|
|
button.parentElement.querySelectorAll(".active")
|
|
.forEach(elem => elem.classList.remove("active"));
|
|
button.classList.add("active");
|
|
section.classList.add("active");
|
|
positionAsTooltip(button, section, {
|
|
horizontal: section.parentElement === menuBar ? "left" : "right",
|
|
vertical: section.parentElement === menuBar ? "bottom" : "top",
|
|
});
|
|
}
|
|
|
|
if (section.parentElement === menuBar) {
|
|
button.addEventListener("click", () => {
|
|
if (section.classList.contains("active")) {
|
|
menuBar.classList.remove("active");
|
|
menuBar.querySelectorAll(".active")
|
|
.forEach(elem => elem.classList.remove("active"));
|
|
activeMenuBar = null;
|
|
} else {
|
|
menuBar.querySelectorAll(".active")
|
|
.forEach(elem => elem.classList.remove("active"));
|
|
menuBar.classList.add("active");
|
|
section.classList.add("active");
|
|
window.addEventListener("click", handleGlobalClick);
|
|
activeMenuBar = menuBar;
|
|
updateActive();
|
|
}
|
|
});
|
|
}
|
|
button.addEventListener("mouseenter", updateActive);
|
|
});
|
|
});
|
|
|
|
// TODO: keyboard navigation with alt and arrow keys
|
|
});
|
|
|
|
|
|
function handleGlobalClick() {
|
|
if (!activeMenuBar) return;
|
|
activeMenuBar.classList.remove("active");
|
|
activeMenuBar.querySelectorAll(".active")
|
|
.forEach(section => section.classList.remove("active"));
|
|
activeMenuBar = null;
|
|
window.removeEventListener("click", handleGlobalClick);
|
|
}
|
|
|
|
function createAltSpan(element, text) {
|
|
const altKey = element.dataset.alt;
|
|
|
|
if (!altKey) {
|
|
const span = document.createElement("span");
|
|
span.appendChild(document.createTextNode(text));
|
|
return span;
|
|
}
|
|
|
|
const [ , before, key, after ] = new RegExp(`^(.*)(${altKey})(.*)$`, "i").exec(text);
|
|
const span = document.createElement("span");
|
|
|
|
if (before) {
|
|
span.appendChild(document.createTextNode(before));
|
|
}
|
|
|
|
const underlineSpan = document.createElement("span");
|
|
underlineSpan.innerText = key;
|
|
underlineSpan.classList.add("alt-key");
|
|
span.appendChild(underlineSpan);
|
|
|
|
if (after) {
|
|
span.appendChild(document.createTextNode(after));
|
|
}
|
|
|
|
return span;
|
|
}
|