streda 1. júla 2009

Workaround for GWT Menubar issue 374

Issue link: Command based top level MenuItems (no sub-menu) stay highlighted when mouse leaves MenuBar.

Short description:

MenuItems on main MenuBar that have no sub-menus stay highlighted even after the mouse leaves the MenuBar. For example the fragment below produces just such a menu...


Workaround:

All workarounds provided on issue page required users to maintain their own GWT builds, which is pretty annoying for such a small nuisance. I have slightly modified one of those solutions, so that now you can package it into your application. It breaks some good practices concerning encapsulation, but it seems to work quite well with GWT 1.6.4. However use only at your own risk.
package com.yourcompany.gwtfix;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;

public class FixedMenuBar extends MenuBar {
    private static final String DEPENDENT_STYLENAME_SELECTED_ITEM = "selected";

    public void onBrowserEvent(Event event) {
        super.onBrowserEvent(event);
        MenuItem item = myFindItem(DOM.eventGetTarget(event));
        if (item == null) {
            return;
        }

        if (DOM.eventGetType(event) == Event.ONMOUSEOUT) {
            this.setSelectionStyle(item, false);
        } else if (DOM.eventGetType(event) == Event.ONMOUSEOVER) {
            this.setSelectionStyle(item, true);
        }
    }

    private void setSelectionStyle(MenuItem item, boolean selected) {
        if (selected) {
            item.addStyleDependentName(DEPENDENT_STYLENAME_SELECTED_ITEM);
        } else {
            item.removeStyleDependentName(DEPENDENT_STYLENAME_SELECTED_ITEM);
        }
    }

    private MenuItem myFindItem(Element hItem) {
        for (MenuItem item : getItems()) {
            if (DOM.isOrHasChild(item.getElement(), hItem))
                return item;
        }
        return null;
    }

    public FixedMenuBar() {
        super();
    }

    public FixedMenuBar(boolean autoClose) {
        super(autoClose);
    }
}