It uses the DOMUtil class, see
/**
* Trigger the display of a menu (MenuBar) based on right-clicking on
some
* Widget.
*
* @author epstein
*/
public class ContextMenuTrigger extends Composite {
/**
* A simple extension of the MenuItem class allowing us to specify
it's
* location and thus, the location of the sub-menu triggered by this
* MenuItem. Used by ContextMenuTrigger, to position the context menu
* (MenuBar) at the mouse's position where the user right-clicked.
*
* @author epstein
*/
private static class PositionableMenuItem extends MenuItem {
int x, y;
/**
* Creates an instance with no text (label) and a null sub-MenuBar.
*/
PositionableMenuItem() {
super("", (MenuBar)null);
}
void setPositionXY(Event event) {
JavaScriptObject intArray = DOMUtil.eventGetXYPosition(event);
x = DOMUtil.getIntAtIndex(intArray, 0);
y = DOMUtil.getIntAtIndex(intArray, 1);
}
/**
* Overridden to return user-specified X location.
*/
public int getAbsoluteLeft() {
return x;
}
/**
* Overridden to return user-specified X location.
*/
public int getAbsoluteTop() {
return y;
}
/**
* Overridden to return 0;
*/
public int getOffsetWidth() {
return 0;
}
/**
* Overridden to return 0;
*/
public int getOffsetHeight() {
return 0;
}
}
private MenuBar menu;
private PositionableMenuItem rootItem;
public ContextMenuTrigger(Widget attachedTo) {
super();
// must call initWidget() in constructor of Composite subclass.
initWidget(attachedTo);
// Mouse triggers the context menu.
this.sinkEvents(Event.MOUSEEVENTS | Event.ONCLICK);
// A dummy MenuBar, allows us to piggy-back on GWT's menu logic.
menu = new MenuBar(true);
rootItem = new ContextMenuTrigger.PositionableMenuItem();
menu.addItem(rootItem);
}
/**
* Get the MenuBar that will be shown on right-click. This is supplied
by
* the user.
*
* @return
*/
public MenuBar getMenuBar() {
return rootItem.getSubMenu();
}
/**
* Allows user to set the MenuBar for right-click activation.
*
* @param aMenu
*/
public void setMenuBar(MenuBar aMenu) {
rootItem.setSubMenu(aMenu);
}
/**
* Re-registers the eventListener for this widget, so we can handle
* right-click.
*/
protected void onAttach() {
super.onAttach();
DOM.setEventListener(this.getElement(), this);
}
/**
* Invoke a MenuBar's doItemAction() method to show a sub-menu
* (sending 'false' as the second parameter). This is a JSNI
* work-around for that method's restricted visibility in Java.
*
* @param menuBar
* the MenuBar on which to invoke the method
* @param item
* the MenuItem to enact
* @see MenuBar#doItemAction(com.google.gwt.user.client.ui.MenuItem,
* boolean)
*/
private native void doItemAction(MenuBar menuBar, final MenuItem item)
/*-{
menuBar.@com.google.gwt.user.client.ui.MenuBar::doItemAction(Lcom/google/gwt/user/client/ui/MenuItem;Z)(item,
false);
}-*/;
/**
* This method handles showing a menu on right-click.
*/
public void onBrowserEvent(Event event) {
if (getMenuBar() == null) {
// Configuration error
throw new Exception("misconfigured context menu, menu bar can't be
null.");
} else if (event != null) {
if (DOM.eventGetType(event) == Event.ONMOUSEDOWN
&& DOM.eventGetButton(event) == Event.BUTTON_RIGHT) {
// TODO : if we're close to the bottom of the window, then
// offset the Y by the height of the to-be-drawn menu,
// and if the result is less than 0, use 0 for Y.
// Similar for X
rootItem.setPositionXY(event);
doItemAction(menu, rootItem);
}
}
}
}
I'm the JWC developer ... When you say the JWC context menu "didn't
work" - what were the problems?
Steve
/* If you don't have one, make a context menu (a GWT MenuBar) */
final MenuBar contextMenuBar = new MenuBar(true);
// Add some items
contextMenuBar.addItem("Context menu item", new Command() {
public void execute() {
Window.alert("Context menu clicked!");
};
});
// Give it a style name (or don't)
contextMenuBar.setStyleName("contextMenuBar");
// Assume you have a widget that wants a context menu
final Widget aWidget = new Label("Right-click on me");
// Create a ContextMenuTrigger which wraps this Widget.
final ContextMenuTrigger widgetWithContextMenu = new
ContextMenuTrigger(aWidget);
// Tell the CM Trigger which menu to show
widgetWithContextMenu.setMenuBar(contextMenuBar);
// Add the widget (with context menu) to a parent element on a page
// by using the ContextMenuTrigger that wraps the original Widget.
RootPanel.get("contextMenuSlot").add(widgetWithContextMenu);
All done. The only nit is you may want to turn off default context
menus on your entire page. This may be a GWT bug but calling
DOM.eventPreventDefault(Event) and DOM.eventCancelBubble(Event, true)
didn't work for me... The fix is to change the regular <body> tag in
your .html file to:
<body oncontextmenu="return false;">
Use the standard GWT style classes to change the background color,
border, etc., etc. See the GWT JavaDocs for info about the style
classes for the GWT widgets.
It worked for me on Firefox just fine.