226 lines
6.2 KiB
JavaScript
226 lines
6.2 KiB
JavaScript
"use strict";
|
|
|
|
// Selection within a MenuBar
|
|
Toolkit.Menu = class Menu extends Toolkit.MenuItem {
|
|
|
|
// Object constructor
|
|
constructor(application, options) {
|
|
super(application, options);
|
|
|
|
// Configure menu element
|
|
this.menu = this.add(this.application.newPanel({
|
|
layout : "flex",
|
|
alignCross: "stretch",
|
|
direction : "column",
|
|
visible : false
|
|
}));
|
|
this.menu.element.style.position = "absolute";
|
|
this.menu.element.setAttribute("role", "menu");
|
|
this.menu.element.setAttribute("aria-labelledby", this.id);
|
|
this.menu.element.addEventListener("pointerdown",e=>this.stopEvent(e));
|
|
this.menu.element.addEventListener("pointermove",e=>this.stopEvent(e));
|
|
this.menu.element.addEventListener("pointerup" ,e=>this.stopEvent(e));
|
|
this.containers.push(this.menu);
|
|
this.children = this.menu.children;
|
|
|
|
// Configure element
|
|
this.element.setAttribute("aria-expanded", "false");
|
|
this.element.setAttribute("aria-haspopup", "menu");
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////// Public Methods //////////////////////////////
|
|
|
|
// Create a MenuItem and associate it with the application and component
|
|
newMenu(options, index) {
|
|
let menu = this.menu.add(new Toolkit.Menu(
|
|
this.application, options), index);
|
|
menu.child();
|
|
menu.element.insertAdjacentElement("afterend", menu.menu.element);
|
|
return menu;
|
|
}
|
|
|
|
// Create a MenuItem and associate it with the application and component
|
|
newMenuItem(options, index) {
|
|
let item = this.menu.add(new Toolkit.MenuItem(
|
|
this.application, options), index);
|
|
item.child();
|
|
return item;
|
|
}
|
|
|
|
// Specify whether the menu is enabled
|
|
setEnabled(enabled) {
|
|
super.setEnabled(enabled);
|
|
if (!this.enabled && this.parent.expanded == this)
|
|
this.setExpanded(false);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////// Package Methods /////////////////////////////
|
|
|
|
// The menu item was activated
|
|
activate(deeper) {
|
|
if (!this.enabled)
|
|
return;
|
|
this.setExpanded(true);
|
|
if (deeper && this.children.length > 0)
|
|
this.children[0].focus();
|
|
}
|
|
|
|
// Show or hide the pop-up menu
|
|
setExpanded(expanded) {
|
|
|
|
// Setting expanded to false
|
|
if (!expanded) {
|
|
|
|
// Hide the pop-up menu
|
|
this.element.setAttribute("aria-expanded", "false");
|
|
this.menu.setVisible(false);
|
|
this.parent.expanded = null;
|
|
|
|
// Close any expanded submenus
|
|
if (this.expanded != null)
|
|
this.expanded.setExpanded(false);
|
|
|
|
return;
|
|
}
|
|
|
|
// Hide the existing submenu of the parent
|
|
if (this.parent.expanded != null && this.parent.expanded != this)
|
|
this.parent.expanded.setExpanded(false);
|
|
this.parent.expanded = this;
|
|
|
|
// Configure element
|
|
this.element.setAttribute("aria-expanded", "true");
|
|
|
|
// Configure pop-up menu
|
|
let barBounds = this.menuBar.element.getBoundingClientRect();
|
|
let bounds = this.element.getBoundingClientRect();
|
|
this.menu.setVisible(true);
|
|
this.menu.setLocation(
|
|
(bounds.x - barBounds.x) + "px",
|
|
(bounds.y + bounds.height - barBounds.y) + "px"
|
|
);
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////// Private Methods /////////////////////////////
|
|
|
|
// Key press event handler
|
|
onkeydown(e) {
|
|
let index;
|
|
|
|
// Processing by key
|
|
switch (e.key) {
|
|
|
|
// Delegate to the MenuItem handler for these keys
|
|
case " " :
|
|
case "ArrowLeft":
|
|
case "End" :
|
|
case "Enter" :
|
|
case "Escape" :
|
|
case "Home" :
|
|
return super.onkeydown(e);
|
|
|
|
// Conditional
|
|
case "ArrowDown":
|
|
|
|
// Open the menu and select the first item (if any)
|
|
if (this.parent == this.menuBar)
|
|
this.activate(true);
|
|
|
|
// Delegate to the MenuItem handler
|
|
else return super.onkeydown(e);
|
|
|
|
break;
|
|
|
|
// Conditional
|
|
case "ArrowRight":
|
|
|
|
// Open the menu and select the first item (if any)
|
|
if (this.parent != this.menuBar)
|
|
this.activate(true);
|
|
|
|
// Delegate to the MenuItem handler
|
|
else return super.onkeydown(e);
|
|
|
|
break;
|
|
|
|
// Conditional
|
|
case "ArrowUp":
|
|
|
|
// Open the menu and select the last item (if any)
|
|
if (this.parent == this.menuBar) {
|
|
this.activate(false);
|
|
index = this.previousChild(0);
|
|
if (index != -1)
|
|
this.children[index].focus();
|
|
}
|
|
|
|
// Delegate to the MenuItem handler
|
|
else return super.onkeydown(e);
|
|
|
|
break;
|
|
|
|
default: return;
|
|
}
|
|
|
|
// Configure event
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
|
|
// Pointer down event handler
|
|
onpointerdown(e) {
|
|
|
|
// Configure event
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
// Error checking
|
|
if (!this.enabled || e.button != 0)
|
|
return;
|
|
|
|
// Activate the menu
|
|
this.focus();
|
|
this.activate(false);
|
|
}
|
|
|
|
// Pointer move event handler
|
|
onpointermove(e) {
|
|
|
|
// Configure event
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
// Error checking
|
|
if (
|
|
this.parent != this.menuBar ||
|
|
this.parent.expanded == null ||
|
|
this.parent.expanded == this
|
|
) return;
|
|
|
|
// Activate the menu
|
|
this.parent.expanded.setExpanded(false);
|
|
this.parent.expanded = this;
|
|
this.focus();
|
|
this.setExpanded(true);
|
|
}
|
|
|
|
// Pointer up event handler (prevent superclass behavior)
|
|
onpointerup(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
|
|
// Prevent an event from bubbling
|
|
stopEvent(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
|
|
};
|