Initial commit: drawNET Alpha v1.0 - Professional Topology Designer with Full i18n and Performance Optimizations

This commit is contained in:
leeyj
2026-03-22 22:37:24 +09:00
commit 5cea93e317
192 changed files with 14449 additions and 0 deletions
@@ -0,0 +1,79 @@
import { state } from '../../state.js';
import { handleMenuAction } from './handlers.js';
import { generateMenuHTML, generateSelectionMenuHTML, showContextMenu, hideContextMenu } from './renderer.js';
let contextMenuElement = null;
/**
* initContextMenu - Initializes the context menu module and event listeners
*/
export function initContextMenu() {
if (contextMenuElement) return;
// 1. Create and Setup Menu Element
contextMenuElement = document.createElement('div');
contextMenuElement.id = 'floating-context-menu';
contextMenuElement.className = 'floating-menu';
contextMenuElement.style.display = 'none';
contextMenuElement.style.position = 'fixed';
contextMenuElement.style.zIndex = '1000';
document.body.appendChild(contextMenuElement);
// 2. Event Listeners for menu items
contextMenuElement.addEventListener('click', (e) => {
const item = e.target.closest('[data-action]');
if (!item) return;
const action = item.getAttribute('data-action');
const cellId = item.getAttribute('data-cell-id');
if (action) {
handleMenuAction(action, cellId);
}
hideContextMenu(contextMenuElement);
});
// Close menu on click outside
document.addEventListener('click', (e) => {
if (contextMenuElement && !contextMenuElement.contains(e.target)) {
hideContextMenu(contextMenuElement);
}
});
if (state.graph) {
// Listen for right click on Graph Cells
state.graph.on('cell:contextmenu', ({ e, cell }) => {
e.preventDefault();
if (state.isRightDragging) return;
// Photoshop-style recursive selection if Ctrl is pressed
if (e.ctrlKey) {
const local = state.graph.clientToLocal(e.clientX, e.clientY);
const models = state.graph.getCells().filter(cell => cell.getBBox().containsPoint(local));
contextMenuElement.innerHTML = generateSelectionMenuHTML(models);
} else {
const selected = state.graph.getSelectedCells();
const nodes = selected.filter(c => c.isNode());
const isGroupSelected = nodes.length === 1 && nodes[0].getData()?.is_group;
contextMenuElement.innerHTML = generateMenuHTML(nodes, isGroupSelected);
}
showContextMenu(contextMenuElement, e.clientX, e.clientY);
});
// Blank context menu (Handle Ctrl+RightClick here too)
state.graph.on('blank:contextmenu', ({ e }) => {
e.preventDefault();
if (state.isRightDragging) return;
if (e.ctrlKey) {
const local = state.graph.clientToLocal(e.clientX, e.clientY);
const models = state.graph.getCells().filter(cell => cell.getBBox().containsPoint(local));
contextMenuElement.innerHTML = generateSelectionMenuHTML(models);
showContextMenu(contextMenuElement, e.clientX, e.clientY);
} else {
hideContextMenu(contextMenuElement);
}
});
}
}