Goondex/internal/web/static/css/gx/GX_ContextMenu.js
Stu Leak 16fb407a3c v0.1.0-dev4: Add web frontend with UI component library
- Implement full web interface with Go html/template server
- Add GX component library (buttons, dialogs, tables, forms, etc.)
- Create scene/performer/studio/movie detail and listing pages
- Add Adult Empire scraper for additional metadata sources
- Implement movie support with database schema
- Add import and sync services for data management
- Include comprehensive API and frontend documentation
- Add custom color scheme and responsive layout

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 10:47:30 -05:00

116 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script>
const gxMenu = document.getElementById("gx-contextmenu");
let gxMenuItems = [];
let gxMenuIndex = -1;
/* ------ OPEN MENU ------ */
function openContextMenu(x, y, items) {
// Build HTML
gxMenu.innerHTML = items.map(item => {
if (item === "divider") {
return `<li class="gx-contextmenu-divider"></li>`;
}
return `
<li class="gx-contextmenu-item" role="menuitem" data-action="${item.action}">
${item.label}
${item.submenu ? `<span class="submenu-arrow"></span>` : ""}
</li>
`;
}).join("");
gxMenuItems = Array.from(gxMenu.querySelectorAll(".gx-contextmenu-item"));
gxMenuIndex = -1;
// Position
gxMenu.style.left = x + "px";
gxMenu.style.top = y + "px";
// Prevent offscreen overflow
const rect = gxMenu.getBoundingClientRect();
if (rect.right > window.innerWidth) {
gxMenu.style.left = (x - rect.width) + "px";
}
if (rect.bottom > window.innerHeight) {
gxMenu.style.top = (y - rect.height) + "px";
}
// Show
gxMenu.classList.add("show");
}
/* ------ CLOSE ------ */
function closeContextMenu() {
gxMenu.classList.remove("show");
gxMenuIndex = -1;
}
/* ------ CLICK HANDLER ------ */
gxMenu.addEventListener("click", e => {
const li = e.target.closest(".gx-contextmenu-item");
if (!li) return;
const action = li.dataset.action;
if (action && window[action]) {
window[action]();
}
closeContextMenu();
});
/* ------ GLOBAL RIGHT CLICK ------ */
document.addEventListener("contextmenu", e => {
e.preventDefault();
const x = e.clientX;
const y = e.clientY;
// Example menu set (replace per-page as needed)
const menuItems = window.getDynamicContextMenu
? window.getDynamicContextMenu(e)
: [
{ label: "Import Performer", action: "importPerformer" },
{ label: "Open Scene", action: "openScene" },
"divider",
{ label: "Copy ID", action: "copyID" },
{ label: "Delete", action: "deleteEntity" }
];
openContextMenu(x, y, menuItems);
});
/* ------ CLICK OUTSIDE ------ */
document.addEventListener("click", e => {
if (!gxMenu.contains(e.target)) closeContextMenu();
});
/* ------ ESC ------ */
document.addEventListener("keydown", e => {
if (e.key === "Escape") closeContextMenu();
});
/* ------ KEYBOARD NAV ------ */
document.addEventListener("keydown", e => {
if (!gxMenu.classList.contains("show")) return;
if (e.key === "ArrowDown") {
e.preventDefault();
gxMenuIndex = (gxMenuIndex + 1) % gxMenuItems.length;
} else if (e.key === "ArrowUp") {
e.preventDefault();
gxMenuIndex = (gxMenuIndex - 1 + gxMenuItems.length) % gxMenuItems.length;
} else if (e.key === "Enter") {
e.preventDefault();
if (gxMenuIndex >= 0) {
const li = gxMenuItems[gxMenuIndex];
const action = li.dataset.action;
if (action && window[action]) window[action]();
}
closeContextMenu();
}
gxMenuItems.forEach(i => i.classList.remove("focused"));
if (gxMenuIndex >= 0) gxMenuItems[gxMenuIndex].classList.add("focused");
});
</script>