"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(); } };