mirror of
https://github.com/NohamR/Pocket-Bird.git
synced 2026-07-10 10:23:05 +00:00
175 lines
4.4 KiB
JavaScript
175 lines
4.4 KiB
JavaScript
import {
|
|
isDebug,
|
|
makeElement,
|
|
onClick,
|
|
makeDraggable,
|
|
makeClosable,
|
|
error
|
|
} from './shared.js';
|
|
|
|
export const MENU_ID = "birb-menu";
|
|
export const MENU_EXIT_ID = "birb-menu-exit";
|
|
|
|
export class MenuItem {
|
|
/**
|
|
* @param {string|(() => string)} text
|
|
* @param {() => void} action
|
|
* @param {number[][]} [icon]
|
|
* @param {boolean} [removeMenu]
|
|
*/
|
|
constructor(text, action, icon, removeMenu = true) {
|
|
this.text = text;
|
|
this.action = action;
|
|
this.icon = icon;
|
|
this.removeMenu = removeMenu;
|
|
}
|
|
}
|
|
|
|
export class ConditionalMenuItem extends MenuItem {
|
|
/**
|
|
* @param {string} text
|
|
* @param {() => void} action
|
|
* @param {() => boolean} condition
|
|
* @param {number[][]} [icon]
|
|
* @param {boolean} [removeMenu]
|
|
*/
|
|
constructor(text, action, condition, icon, removeMenu = true) {
|
|
super(text, action, icon, removeMenu);
|
|
this.condition = condition;
|
|
}
|
|
}
|
|
|
|
export class DebugMenuItem extends ConditionalMenuItem {
|
|
/**
|
|
* @param {string} text
|
|
* @param {() => void} action
|
|
*/
|
|
constructor(text, action, removeMenu = true) {
|
|
super(text, action, () => isDebug(), undefined, removeMenu);
|
|
}
|
|
}
|
|
|
|
export class Separator extends MenuItem {
|
|
constructor() {
|
|
super("", () => { });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {MenuItem} item
|
|
* @param {() => void} removeMenuCallback
|
|
* @returns {HTMLElement}
|
|
*/
|
|
function createMenuItem(item, removeMenuCallback) {
|
|
if (item instanceof Separator) {
|
|
return makeElement("birb-window-separator");
|
|
}
|
|
let menuItem = makeElement("birb-menu-item", typeof item.text === "function" ? item.text() : item.text);
|
|
if (item.icon) {
|
|
const iconCanvas = document.createElement("canvas");
|
|
iconCanvas.width = 7;
|
|
iconCanvas.height = 6;
|
|
iconCanvas.classList.add("birb-menu-item-icon");
|
|
const ctx = iconCanvas.getContext("2d");
|
|
if (ctx) {
|
|
for (let row = 0; row < item.icon.length; row++) {
|
|
for (let col = 0; col < item.icon[row].length; col++) {
|
|
if (item.icon[row][col]) {
|
|
ctx.fillStyle = "black";
|
|
ctx.fillRect(col, row, 1, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
menuItem.prepend(iconCanvas);
|
|
}
|
|
onClick(menuItem, () => {
|
|
if (item.removeMenu) {
|
|
removeMenuCallback();
|
|
}
|
|
item.action();
|
|
});
|
|
return menuItem;
|
|
}
|
|
|
|
/**
|
|
* Add the menu to the page if it doesn't already exist
|
|
* @param {MenuItem[]} menuItems
|
|
* @param {string} title
|
|
* @param {(menu: HTMLElement) => void} updateLocationCallback
|
|
*/
|
|
export function insertMenu(menuItems, title, updateLocationCallback) {
|
|
if (document.querySelector("#" + MENU_ID)) {
|
|
return;
|
|
}
|
|
let menu = makeElement("birb-window", undefined, MENU_ID);
|
|
let header = makeElement("birb-window-header");
|
|
const titleDiv = makeElement("birb-window-title", title);
|
|
header.appendChild(titleDiv);
|
|
let content = makeElement("birb-window-content");
|
|
const removeCallback = () => removeMenu();
|
|
for (const item of menuItems) {
|
|
if (!(item instanceof ConditionalMenuItem) || item.condition()) {
|
|
content.appendChild(createMenuItem(item, removeCallback));
|
|
}
|
|
}
|
|
menu.appendChild(header);
|
|
menu.appendChild(content);
|
|
document.body.appendChild(menu);
|
|
makeDraggable(document.querySelector(".birb-window-header"));
|
|
|
|
let menuExit = makeElement("birb-window-exit", undefined, MENU_EXIT_ID);
|
|
onClick(menuExit, removeCallback);
|
|
document.body.appendChild(menuExit);
|
|
makeClosable(removeCallback);
|
|
|
|
updateLocationCallback(menu);
|
|
}
|
|
|
|
/**
|
|
* Remove the menu from the page
|
|
*/
|
|
export function removeMenu() {
|
|
const menu = document.querySelector("#" + MENU_ID);
|
|
if (menu) {
|
|
menu.remove();
|
|
}
|
|
const exitMenu = document.querySelector("#" + MENU_EXIT_ID);
|
|
if (exitMenu) {
|
|
exitMenu.remove();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @returns {boolean} Whether the menu element is on the page
|
|
*/
|
|
export function isMenuOpen() {
|
|
return document.querySelector("#" + MENU_ID) !== null;
|
|
}
|
|
|
|
/**
|
|
* @param {MenuItem[]} menuItems
|
|
* @param {(menu: HTMLElement) => void} updateLocationCallback
|
|
*/
|
|
export function switchMenuItems(menuItems, updateLocationCallback) {
|
|
const menu = document.querySelector("#" + MENU_ID);
|
|
if (!menu || !(menu instanceof HTMLElement)) {
|
|
return;
|
|
}
|
|
const content = menu.querySelector(".birb-window-content");
|
|
if (!content) {
|
|
error("Birb: Content not found");
|
|
return;
|
|
}
|
|
while (content.firstChild) {
|
|
content.removeChild(content.firstChild);
|
|
}
|
|
const removeCallback = () => removeMenu();
|
|
for (const item of menuItems) {
|
|
if (!(item instanceof ConditionalMenuItem) || item.condition()) {
|
|
content.appendChild(createMenuItem(item, removeCallback));
|
|
}
|
|
}
|
|
updateLocationCallback(menu);
|
|
}
|