Files
scaenae/js/controllers/menu_controller.js
2026-04-22 10:30:04 +02:00

110 lines
3.5 KiB
JavaScript

// Global ATON
import { Controller } from "@hotwired/stimulus"
import AppState from "../state.js";
import { traverseOntology } from "../ontology.js";
const html = String.raw;
const domParser = new DOMParser;
// TODO: hard-coded, but follows a convention...
const ontologyJsonPath = location.pathname + 'ontology.json';
export default class extends Controller {
static targets = ['trigger', 'layers', 'ontology'];
connect() {
console.log('#menu controller connected');
}
/**
* Open settings panel
* @param {Event} event
*/
async toggleMenu() {
ATON.UI.setSidePanelRight();
ATON.UI.showSidePanel({header: 'Menu'});
this.#buildMenuPanel(ATON.UI.elSidePanel);
this.#buildLayersMenu(AppState.normalizedNodes, this.layersTarget);
this.#buildOntologyMenu(await traverseOntology(ontologyJsonPath), this.ontologyTarget);
}
/**
* @param {Event} event
*/
toggleNode(event) {
/**
* The node's id
* @type {string}
*/
const id = event.params.node;
const status = event.target.checked;
ATON.getSceneNode(id).toggle(status);
AppState.normalizedNodes.find(n => n.id === id).active = status;
}
/**
* Clone a <template> by id
* @param {String} id
* @returns {DocumentFragment}
*/
#cloneTemplate(id) {
return document.getElementById(id).content.cloneNode(true);
}
/**
* Create the left-side settings panel
* content
* @param {Element} panel
*/
#buildMenuPanel(panel) {
const fragment = this.#cloneTemplate('tmpl-menu-tabs');
panel.appendChild(fragment);
}
/**
* @todo Don't rebuild it every time, use caching, return a container with checkboxes
* @param {Array} nodes The normalized scene nodes (IDs and status)
* @param {HTMLElement} tab Tab content element
*/
#buildLayersMenu(nodes, tab) {
for(let node of nodes) {
const menuItem = html`
<div class="form-check form-switch ms-${node.depth} ps-${node.depth} mt-2">
<input class="form-check-input" type="checkbox" ${node.active ? 'checked' : ''} role="switch"
title="Mostra / nascondi layer"
data-menu-node-param="${node.id}"
data-action="change->menu#toggleNode">
<label class="form-check-label">${node.id}</label>
</div>
`;
// Awful?
tab.appendChild(
domParser.parseFromString(menuItem, 'text/html').querySelector('div')
);
}
}
/**
* Temporary implementation to show domains only
* @todo Don't rebuild it every time, use caching, return a container
* @param {Object} ontology The traversed ontology object (temp)
* @param {HTMLElement} tab Tab content element
*/
#buildOntologyMenu(ontology, tab) {
console.debug(ontology);
const mainNode = tab.querySelector('#ontology-list');
mainNode.textContent = ontology.ontology;
let domainList = html`
<ul class="list-group mt-2" id="domains-list"></ul>
`;
// Very fragile and ugly!!
mainNode.innerHTML += domainList;
domainList = tab.querySelector('#domains-list');
for(let domain of ontology.domains) {
const domainItem = html`
<li class="list-group-item">${domain.label}</li>
`;
domainList.innerHTML += domainItem;
}
}
}