Helps to provide menu like UI.
The menu will behave similar to a native menu UI for major operations via the pointing device and the keyboard).
Load the file MenuUI.js
from any visible document (sidebar panel or browser action panel), like:
<script type="application/javascript" src="./MenuUI.js"></script>
And define hierarchical menu based on ul
-li
list, like:
<ul id="menu">
<li>&Save</li>
<li>Co&py
<ul>
<li>&Title</li>
<li>&URL</li>
<li>&Metadata
<ul>
<li>&Author</li>
<li>&Email</li>
</ul>
</li>
</ul>
</li>
<li class="separator"></li>
<li>&Close</li>
</ul>
Then, create an instance of MenuUI
with required parameters like:
var menuUI = new MenuUI({
root: document.getElementById('menu'),
onCommand: (aItem, aEvent) => {
// handle click event on an item
}
});
Now you can open/close menu-like UI by its instance method:
window.addEventListener('contextmenu', aEvent => {
aEvent.stopPropagation();
aEvent.preventDefault();
// open custom menu instead of native context menu
menuUI.open({
left: aEvent.clientX,
top: aEvent.clientY
});
});
Here is the list of parameters for the MenuUI
constructor:
root
(required): The top-level list to become a menu. (Element
)onCommand
(required): The handler for click event on a menu item. (Function
)onShown
(optional): The handler called when the menu is shown (opened). (Function
)onHidden
(optional): The handler called when the menu is hidden (closed). (Function
)appearance
(optional): The visual style of the menu. (String
, default ismenu
.) Possible values:menu
: similar to native menu UI.panel
: similar to popup panel UI.
animationDuration
(optional): The duration of the animation of fade-in-out effect, in milliseconds. (Integer
, default value is150
.)subMenuOpenDelay
(optional): The delay when a submenu is opened after its parent item is pointed, in milliseconds. (Integer
, default value is300
.)subMenuCloseDelay
(optional): The delay when a submenu is closed after foreign item is pointed, in milliseconds. (Integer
, default value is300
.)incrementalSearch
(optional): Activate incremental search mode or not. (Boolean
, default value isfalse
.)incrementalSearchTimeout
(optional): Timeout seconds to clear last incremental search buffer. (Integer
, default value is1000
.)
The instance method open()
opens the menu. You can specify the position of the opened menu in two ways:
Specifying corrdinates via left
and top
will show the menu near given coordinates. Typically this form is useful to open menu based on mouse events, like:
window.addEventListener('click', aEvent => {
menuUI.open({
left: aEvent.clientX,
top: aEvent.clientY
});
});
Specifying an element via anchor
will show the menu near the element. Typically this form is useful to open menu as a dropdown or popup, like:
const button = document.getElementById('button');
button.addEventListener('click', () => {
menuUI.open({
anchor: button
});
});
The open()
instance method accepts one more optional parameter, canceller
. It is a function returning boolean value, and the opening operation of the menu will be canceled if the function returns false
. For example:
let canceled = false;
button.addEventListener('click', () => {
menuUI.open({
left: aEvent.clientX,
top: aEvent.clientY,
canceller: () => {
return canceled;
}
});
});
button.addEventListener('dblclick', () => {
canceled = true;
menuUI.close();
});
On this case, if you double-click the button, the menu won't be shown.
Calling an instance method close()
will close the opened menu. This method will close all submenus also.
There is an instance property opened
. It returns a boolean value and true
means "opened", false
means "closed".
A function specified via the onCommand
parameter for the constructor will be called when a menu item without submenu is triggered. The function will receive the triggered menu item as its first argument. The second argument is the raw DOM event. Then you can do anything for the item.
var menuUI = new MenuUI({
root: document.getElementById('menu'),
onCommand: (aItem, aEvent) => {
switch (aItem.id) {
case 'command1':
doCommand1();
break;
case 'command2':
doCommand2();
break;
default:
doGenericCommand(aItem.dataset.value);
break;
}
menuUI.close();
}
});
Note that the menu is not closed automatically by clicking on a menu item. You need to close the menu itself manually after doing something.
Blank <li>
elements with a class separator
are treated as menu separator.
If the label of a menu item contains a part &
(&
in HTML) followed by an non-whitespace character (like &A
), the character following to the &
will be treated as the accesskey of the item.