Package com.extjs.gxt.ui.client.widget.menu

Source Code of com.extjs.gxt.ui.client.widget.menu.Menu

/*
* Ext GWT 2.2.4 - Ext for GWT
* Copyright(c) 2007-2010, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
package com.extjs.gxt.ui.client.widget.menu;

import com.extjs.gxt.ui.client.GXT;
import com.extjs.gxt.ui.client.Style;
import com.extjs.gxt.ui.client.Style.HideMode;
import com.extjs.gxt.ui.client.aria.FocusFrame;
import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.core.XDOM;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.ClickRepeaterEvent;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.ContainerEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MenuEvent;
import com.extjs.gxt.ui.client.event.PreviewEvent;
import com.extjs.gxt.ui.client.util.BaseEventPreview;
import com.extjs.gxt.ui.client.util.ClickRepeater;
import com.extjs.gxt.ui.client.util.KeyNav;
import com.extjs.gxt.ui.client.util.Point;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.Container;
import com.extjs.gxt.ui.client.widget.Layout;
import com.extjs.gxt.ui.client.widget.layout.MenuLayout;
import com.google.gwt.dom.client.EventTarget;
import com.google.gwt.dom.client.NodeList;
import com.google.gwt.event.dom.client.KeyCodes;
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.Accessibility;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;

/**
* A menu component.
*
* <dl>
* <dt><b>Events:</b></dt>
*
* <dd><b>BeforeShow</b> : MenuEvent(container)<br>
* <div>Fires before this menu is displayed. Listeners can cancel the action by
* calling {@link BaseEvent#setCancelled(boolean)}.</div>
* <ul>
* <li>container : this</li>
* </ul>
* </dd>
*
* <dd><b>Show</b> : MenuEvent(container)<br>
* <div>Fires after this menu is displayed.</div>
* <ul>
* <li>container : this</li>
* </ul>
* </dd>
*
* <dd><b>BeforeHide</b> : MenuEvent(container)<br>
* <div>Fired before the menu is hidden. Listeners can cancel the action by
* calling {@link BaseEvent#setCancelled(boolean)}.</div>
* <ul>
* <li>container : this</li>
* </ul>
* </dd>
*
* <dd><b>Hide</b> : MenuEvent(container)<br>
* <div>Fires after this menu is hidden.</div>
* <ul>
* <li>container : this</li>
* </ul>
* </dd>
*
* <dd><b>BeforeAdd</b> : MenuEvent(container, item, index)<br>
* <div>Fires before a item is added or inserted. Listeners can cancel the
* action by calling {@link BaseEvent#setCancelled(boolean)}.</div>
* <ul>
* <li>container : this</li>
* <li>item : the item being added</li>
* <li>index : the index at which the item will be added</li>
* </ul>
* </dd>
*
* <dd><b>BeforeRemove</b> : MenuEvent(container, item)<br>
* <div>Fires before a item is removed. Listeners can cancel the action by
* calling {@link BaseEvent#setCancelled(boolean)}.</div>
* <ul>
* <li>container : this</li>
* <li>item : the item being removed</li>
* </ul>
* </dd>
*
* <dd><b>Add</b> : MenuEvent(container, item, index)<br>
* <div>Fires after a item has been added or inserted.</div>
* <ul>
* <li>container : this</li>
* <li>item : the item that was added</li>
* <li>index : the index at which the item will be added</li>
* </ul>
* </dd>
*
* <dd><b>Remove</b> : MenuEvent(container, item)<br>
* <div>Fires after a item has been removed.</div>
* <ul>
* <li>container : this</li>
* <li>item : the item being removed</li>
* </ul>
* </dd>
* </dl>
*
* <dl>
* <dt>Inherited Events:</dt>
* <dd>BoxComponent Move</dd>
* <dd>BoxComponent Resize</dd>
* <dd>Component Enable</dd>
* <dd>Component Disable</dd>
* <dd>Component BeforeHide</dd>
* <dd>Component Hide</dd>
* <dd>Component BeforeShow</dd>
* <dd>Component Show</dd>
* <dd>Component Attach</dd>
* <dd>Component Detach</dd>
* <dd>Component BeforeRender</dd>
* <dd>Component Render</dd>
* <dd>Component BrowserEvent</dd>
* <dd>Component BeforeStateRestore</dd>
* <dd>Component StateRestore</dd>
* <dd>Component BeforeStateSave</dd>
* <dd>Component SaveState</dd>
* </dl>
*/
public class Menu extends Container<Component> {

  protected KeyNav<ComponentEvent> keyNav;
  protected Item parentItem;
  protected BaseEventPreview eventPreview;
  protected boolean plain;
  protected boolean showSeparator = true;
  protected El ul;
  protected Item activeItem;

  private String subMenuAlign = "tl-tr?";
  private String defaultAlign = "tl-bl?";

  private int minWidth = 120;
  private boolean showing;
  private boolean constrainViewport = true;
  private boolean focusOnShow = true;
  private int maxHeight = Style.DEFAULT;
  private boolean enableScrolling = true;
  private int scrollIncrement = 24;
  private int scrollerHeight = 8;
  private int activeMax;

  /**
   * Creates a new menu.
   */
  public Menu() {
    baseStyle = "x-menu";
    shim = true;
    monitorWindowResize = true;
    setShadow(true);
    setLayoutOnChange(true);

    enableLayout = true;
    setLayout(new MenuLayout());
    eventPreview = new BaseEventPreview() {

      @Override
      protected boolean onPreview(PreviewEvent pe) {
        Menu.this.onAutoHide(pe);
        return super.onPreview(pe);
      }

      @Override
      protected void onPreviewKeyPress(PreviewEvent pe) {
        super.onPreviewKeyPress(pe);
        onEscape(pe);
      }
    };
  }

  /**
   * Adds a item to the menu.
   *
   * @param item the new item
   */
  @Override
  public boolean add(Component item) {
    return super.add(item);
  }

  /**
   * Returns the default alignment.
   *
   * @return the default align
   */
  public String getDefaultAlign() {
    return defaultAlign;
  }

  @Override
  public El getLayoutTarget() {
    return ul;
  }

  /**
   * Returns the max height of the menu or -1 if not set.
   *
   * @return the max height in pixels
   */
  public int getMaxHeight() {
    return maxHeight;
  }

  /**
   * Returns the menu's minimum width.
   *
   * @return the width
   */
  public int getMinWidth() {
    return minWidth;
  }

  /**
   * Returns the menu's parent item.
   *
   * @return the parent item
   */
  public Item getParentItem() {
    return parentItem;
  }

  /**
   * Returns the sub menu alignment.
   *
   * @return the alignment
   */
  public String getSubMenuAlign() {
    return subMenuAlign;
  }

  /**
   * Hides the menu.
   */
  public void hide() {
    hide(false);
  }

  /**
   * Hides this menu and optionally all parent menus
   *
   * @param deep true to close all parent menus
   * @return this
   */
  public Menu hide(boolean deep) {
    if (showing) {
      MenuEvent me = new MenuEvent(this);
      if (fireEvent(Events.BeforeHide, me)) {
        if (activeItem != null) {
          activeItem.deactivate();
          activeItem = null;
        }
        onHide();
        RootPanel.get().remove(this);
        eventPreview.remove();
        showing = false;
        hidden = true;
        fireEvent(Events.Hide, me);
        if (deep && parentItem != null) {
          parentItem.parentMenu.hide(true);
        }
      }
    }
    return this;
  }

  /**
   * Inserts an item into the menu.
   *
   * @param item the item to insert
   * @param index the insert location
   */
  @Override
  public boolean insert(Component item, int index) {
    if (item instanceof Item) {
      ((Item) item).parentMenu = this;
    }
    return super.insert(item, index);
  }

  /**
   * Returns true if constrain to viewport is enabled.
   *
   * @return the constrain to viewport state
   */
  public boolean isConstrainViewport() {
    return constrainViewport;
  }

  /**
   * Returns true if vertical scrolling is enabled.
   *
   * @return true for scrolling
   */
  public boolean isEnableScrolling() {
    return enableScrolling;
  }

  /**
   * Returns true if the menu will be focused when displayed.
   *
   * @return true if focused
   */
  public boolean isFocusOnShow() {
    return focusOnShow;
  }

  @Override
  public boolean isVisible() {
    return showing;
  }

  @Override
  public void onComponentEvent(ComponentEvent ce) {
    super.onComponentEvent(ce);
    switch (ce.getEventTypeInt()) {
      case Event.ONCLICK:
        onClick(ce);
        break;
      case Event.ONMOUSEMOVE:
        onMouseMove(ce);
        break;
      case Event.ONMOUSEOUT:
        onMouseOut(ce);
        break;
      case Event.ONMOUSEOVER:
        onMouseOver(ce);
        break;
      case Event.ONMOUSEWHEEL:
        if (enableScrolling) {
          scrollMenu(ce.getEvent().getMouseWheelVelocityY() < 0);
        }
    }
    El t = ce.getTargetEl();
    if (enableScrolling && t.is(".x-menu-scroller")) {
      switch (ce.getEventTypeInt()) {
        case Event.ONMOUSEOVER:
          // deactiveActiveItem();
          onScrollerIn(t);
          break;
        case Event.ONMOUSEOUT:
          onScrollerOut(t);
          break;
      }
    }
  }

  /**
   * Removes a item from the menu.
   *
   * @param item the menu to remove
   */
  @Override
  public boolean remove(Component item) {
    if (activeItem == item) {
      deactiveActiveItem();
    }
    boolean success = super.remove(item);
    if (success && item instanceof Item) {
      ((Item) item).parentMenu = null;
    }
    return success;
  }

  /**
   * Sets the active item. The component must be of type <code>Item</code> to be
   * activated. All other types are ignored.
   *
   * @param c the component to set active
   * @param autoExpand true to auto expand the item
   */
  public void setActiveItem(Component c, boolean autoExpand) {
    if (c == null) {
      deactiveActiveItem();
      return;
    }
    if (c instanceof Item) {
      Item item = (Item) c;
      if (item != activeItem) {
        deactiveActiveItem();

        this.activeItem = item;
        item.activate(autoExpand);
        item.el().scrollIntoView(ul.dom, false);
        focus();

        if (GXT.isFocusManagerEnabled()) {
          FocusFrame.get().frame(item);
          Accessibility.setState(getElement(), "aria-activedescendant", item.getId());
        }

      } else if (autoExpand) {
        item.expandMenu(autoExpand);
      }
    }
  }

  /**
   * Sets whether the menu should be constrained to the viewport when shown.
   * Only applies when using {@link #showAt(int, int)}.
   *
   * @param constrainViewport true to constrain
   */
  public void setConstrainViewport(boolean constrainViewport) {
    this.constrainViewport = constrainViewport;
  }

  /**
   * Sets the default {@link El#alignTo} anchor position value for this menu
   * relative to its element of origin (defaults to "tl-bl?").
   *
   * @param defaultAlign the default align
   */
  public void setDefaultAlign(String defaultAlign) {
    this.defaultAlign = defaultAlign;
  }

  /**
   * True to enable vertical scrolling of the children in the menu (defaults to
   * true).
   *
   * @param enableScrolling true to for scrolling
   */
  public void setEnableScrolling(boolean enableScrolling) {
    this.enableScrolling = enableScrolling;
  }

  /**
   * True to set the focus on the menu when it is displayed.
   *
   * @param focusOnShow true to focus
   */
  public void setFocusOnShow(boolean focusOnShow) {
    this.focusOnShow = focusOnShow;
  }

  /**
   * Sets the max height of the menu (defaults to -1). Only applies when
   * {@link #setEnableScrolling(boolean)} is set to true.
   *
   * @param maxHeight the max height
   */
  public void setMaxHeight(int maxHeight) {
    this.maxHeight = maxHeight;
  }

  /**
   * Sets he minimum width of the menu in pixels (defaults to 120).
   *
   * @param minWidth the min width
   */
  public void setMinWidth(int minWidth) {
    this.minWidth = minWidth;
  }

  /**
   * The {@link El#alignTo} anchor position value to use for submenus of this
   * menu (defaults to "tl-tr-?").
   *
   * @param subMenuAlign the sub alignment
   */
  public void setSubMenuAlign(String subMenuAlign) {
    this.subMenuAlign = subMenuAlign;
  }

  /**
   * Displays this menu relative to another element.
   *
   * @param elem the element to align to
   * @param pos the {@link El#alignTo} anchor position to use in aligning to the
   *          element (defaults to defaultAlign)
   */
  public void show(Element elem, String pos) {
    show(elem, pos, new int[] {0, 0});
  }

  /**
   * Displays this menu relative to another element.
   *
   * @param elem the element to align to
   * @param pos the {@link El#alignTo} anchor position to use in aligning to the
   *          element (defaults to defaultAlign)
   * @param offsets the menu align offsets
   */
  public void show(Element elem, String pos, int[] offsets) {
    MenuEvent me = new MenuEvent(this);
    if (fireEvent(Events.BeforeShow, me)) {
      RootPanel.get().add(this);

      el().makePositionable(true);

      onShow();
      el().updateZIndex(0);

      showing = true;
      doAutoSize();

      el().alignTo(elem, pos, offsets);

      if (enableScrolling) {
        constrainScroll(el().getY());
      }
      el().show();

      eventPreview.add();

      if (focusOnShow) {
        focus();
      }

      fireEvent(Events.Show, me);
    }
  }

  /**
   * Displays this menu relative to the widget using the default alignment.
   *
   * @param widget the align widget
   */
  public void show(Widget widget) {
    show(widget.getElement(), defaultAlign);
  }

  /**
   * Displays this menu at a specific xy position.
   *
   * @param x the x coordinate
   * @param y the y coordinate
   */
  public void showAt(int x, int y) {
    MenuEvent me = new MenuEvent(this);
    if (fireEvent(Events.BeforeShow, me)) {
      RootPanel.get().add(this);

      el().makePositionable(true);

      onShow();
      el().updateZIndex(0);

      showing = true;
      doAutoSize();

      if (constrainViewport) {
        Point p = el().adjustForConstraints(new Point(x, y));
        x = p.x;
        y = p.y;
      }
      setPagePosition(x + XDOM.getBodyScrollLeft(), y + XDOM.getBodyScrollTop());
      if (enableScrolling) {
        constrainScroll(y);
      }

      el().show();
      eventPreview.add();

      if (focusOnShow) {
        focus();
      }

      fireEvent(Events.Show, me);
    }
  }

  @Override
  protected void afterRender() {
    super.afterRender();

    keyNav = new KeyNav<ComponentEvent>(this) {
      public void onDown(ComponentEvent ce) {
        onKeyDown(ce);
      }

      public void onEnter(ComponentEvent be) {
        if (activeItem != null) {
          be.cancelBubble();
          activeItem.onClick(be);
        }
      }

      public void onLeft(ComponentEvent be) {
        hide();
        if (parentItem != null) {
          parentItem.parentMenu.focus();
          if (GXT.isFocusManagerEnabled()) {
            FocusFrame.get().frame(parentItem);
          }
        } else {
          Menu menu = Menu.this;
          while (menu.parentItem != null) {
            menu = menu.parentItem.parentMenu;
          }
          menu.fireEvent(Events.Minimize);
        }
      }

      public void onRight(ComponentEvent be) {
        if (activeItem != null) {
          activeItem.expandMenu(true);
        }
        if (activeItem instanceof MenuItem) {
          MenuItem mi = (MenuItem) activeItem;
          if (mi.subMenu != null && mi.subMenu.isVisible()) {
            return;
          }
        }
        Menu menu = Menu.this;
        while (menu.parentItem != null) {
          menu = menu.parentItem.parentMenu;
        }
        menu.fireEvent(Events.Maximize);
      }

      public void onUp(ComponentEvent ce) {
        onKeyUp(ce);
      }
    };
  }

  protected void constrainScroll(int y) {
    int full = ul.setHeight("auto").getHeight();

    int max = maxHeight != Style.DEFAULT ? maxHeight : (XDOM.getViewHeight(false) - y);
    if (full > max && max > 0) {
      activeMax = max - 10 - scrollerHeight * 2;
      ul.setHeight(activeMax, true);
      createScrollers();
    } else {
      ul.setHeight(full, true);
      NodeList<Element> nodes = el().select(".x-menu-scroller");
      for (int i = 0; i < nodes.getLength(); i++) {
        fly(nodes.getItem(i)).hide();
      }
    }
    ul.setScrollTop(0);
  }

  @Override
  protected ComponentEvent createComponentEvent(Event event) {
    return new MenuEvent(this);
  }

  @Override
  protected ContainerEvent<Menu, Component> createContainerEvent(Component item) {
    return new MenuEvent(this, item);
  }

  protected void createScrollers() {
    if (el().select(".x-menu-scroller").getLength() == 0) {
      Listener<ClickRepeaterEvent> listener = new Listener<ClickRepeaterEvent>() {
        public void handleEvent(ClickRepeaterEvent be) {
          onScroll(be);
        }
      };

      El scroller;

      scroller = new El(DOM.createDiv());
      scroller.addStyleName("x-menu-scroller", "x-menu-scroller-top");
      scroller.setInnerHtml("&nbsp;");
      ClickRepeater cr = new ClickRepeater(scroller);
      cr.doAttach();
      cr.addListener(Events.OnClick, listener);
      addAttachable(cr);

      el().insertFirst(scroller.dom);

      scroller = new El(DOM.createDiv());
      scroller.addStyleName("x-menu-scroller", "x-menu-scroller-bottom");
      scroller.setInnerHtml("&nbsp;");
      cr = new ClickRepeater(scroller);
      cr.doAttach();
      cr.addListener(Events.OnClick, listener);
      addAttachable(cr);

      el().appendChild(scroller.dom);
    }
  }

  protected void deactiveActiveItem() {
    if (activeItem != null) {
      activeItem.deactivate();
      activeItem = null;
    }
    if (GXT.isFocusManagerEnabled()) {
      FocusFrame.get().unframe();
      Accessibility.setState(getElement(), "aria-activedescendant", "");
    }
  }

  protected void doAutoSize() {
    if (showing && width == null) {
      int width = getLayoutTarget().getWidth() + el().getFrameWidth("lr");
      el().setWidth(Math.max(width, minWidth), true);
    }
  }

  protected boolean onAutoHide(PreviewEvent pe) {
    if ((pe.getEventTypeInt() == Event.ONMOUSEDOWN || pe.getEventTypeInt() == Event.ONMOUSEWHEEL
        || pe.getEventTypeInt() == Event.ONSCROLL || pe.getEventTypeInt() == Event.ONKEYPRESS)
        && !(pe.within(getElement()) || (fly(pe.getTarget()).findParent(".x-ignore", -1) != null))) {
      MenuEvent me = new MenuEvent(this);
      me.setEvent(pe.getEvent());
      if (fireEvent(Events.AutoHide, me)) {
        hide(true);
        return true;
      }
    }
    return false;
  }

  protected void onClick(ComponentEvent ce) {
    Component item = findItem(ce.getTarget());
    if (item != null && item instanceof Item) {
      ((Item) item).onClick(ce);
    }
  }

  @Override
  protected void onDetach() {
    super.onDetach();
    if (eventPreview != null) {
      eventPreview.remove();
    }
  }

  protected void onEscape(PreviewEvent pe) {
    if (pe.getKeyCode() == KeyCodes.KEY_ESCAPE) {
      if (activeItem != null && !activeItem.onEscape()) {
        return;
      }
      hide(false);
    }
  }

  @Override
  protected void onHide() {
    super.onHide();
    deactiveActiveItem();
  }

  @Override
  protected void onInsert(Component item, int index) {
    super.onInsert(item, index);
    if (rendered && GXT.isAriaEnabled() && item instanceof CheckMenuItem) {
      handleRadioGroups();
    }
  }

  protected void onKeyDown(ComponentEvent ce) {
    ce.stopEvent();
    if (tryActivate(indexOf(activeItem) + 1, 1) == null) {
      tryActivate(0, 1);
    }
  }

  protected void onKeyUp(ComponentEvent ce) {
    ce.stopEvent();
    if (tryActivate(indexOf(activeItem) - 1, -1) == null) {
      tryActivate(getItemCount() - 1, -1);
    }
  }

  @Override
  protected void onLayoutExcecuted(Layout layout) {
    super.onLayoutExcecuted(layout);
    doAutoSize();
  }

  protected void onMouseMove(ComponentEvent ce) {
    Component c = findItem(ce.getTarget());
    if (c != null && c instanceof Item) {
      Item item = (Item) c;
      if (activeItem != item && item.canActivate && item.isEnabled()) {
        setActiveItem(item, true);
      }
    }
  }

  protected void onMouseOut(ComponentEvent ce) {
    EventTarget to = ce.getEvent().getRelatedEventTarget();
    if (activeItem != null
        && (to == null || (Element.is(to) && !DOM.isOrHasChild(activeItem.getElement(), (Element) Element.as(to))))
        && activeItem.shouldDeactivate(ce)) {
      deactiveActiveItem();
    }
  }

  protected void onMouseOver(ComponentEvent ce) {
    EventTarget from = ce.getEvent().getRelatedEventTarget();
    if (from == null || (Element.is(from) && !DOM.isOrHasChild(getElement(), (Element) Element.as(from)))) {
      Component c = findItem(ce.getTarget());
      if (c != null && c instanceof Item) {
        Item item = (Item) c;
        if (activeItem != item && item.canActivate && item.isEnabled()) {
          setActiveItem(item, true);
        }
      }
    }
  }

  @Override
  protected void onRemove(Component item) {
    super.onRemove(item);
    if (rendered && GXT.isAriaEnabled() && item instanceof CheckMenuItem) {
      handleRadioGroups();
    }
  }

  @Override
  protected void onRender(Element target, int index) {
    setElement(DOM.createDiv(), target, index);
    el().makePositionable(true);
    super.onRender(target, index);

    ul = new El(DOM.createDiv());
    ul.addStyleName(baseStyle + "-list");

    getElement().appendChild(ul.dom);

    // add menu to ignore list
    eventPreview.getIgnoreList().add(getElement());

    el().setTabIndex(0);
    el().setElementAttribute("hideFocus", "true");

    el().addStyleName("x-ignore");
    if (GXT.isAriaEnabled()) {
      Accessibility.setRole(getElement(), "menu");
      Accessibility.setRole(ul.dom, "presentation");
      handleRadioGroups();
    }

    if (plain) {
      addStyleName("x-menu-plain");
    }
    if (!showSeparator) {
      addStyleName("x-menu-nosep");
    }

    sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.KEYEVENTS | Event.ONMOUSEWHEEL);
  }

  protected void onScroll(ClickRepeaterEvent ce) {
    El target = ce.getEl();
    boolean top = target.is(".x-menu-scroller-top");
    scrollMenu(top);

    if (top ? ul.getScrollTop() <= 0 : ul.getScrollTop() + activeMax >= ul.dom.getPropertyInt("scrollHeight")) {
      onScrollerOut(target);
    }
  }

  protected void onScrollerIn(El t) {
    boolean top = t.is(".x-menu-scroller-top");
    if (top ? ul.getScrollTop() > 0 : ul.getScrollTop() + activeMax < ul.dom.getPropertyInt("scrollHeight")) {
      t.addStyleName("x-menu-item-active", "x-menu-scroller-active");
    }
  }

  protected void onScrollerOut(El t) {
    t.removeStyleName("x-menu-item-active", "x-menu-scroller-active");
  }

  @Override
  protected void onWindowResize(int width, int height) {
    hide(true);
  }

  protected void scrollMenu(boolean top) {
    ul.setScrollTop(ul.getScrollTop() + scrollIncrement * (top ? -1 : 1));
  }

  protected Item tryActivate(int start, int step) {
    for (int i = start, len = getItemCount(); i >= 0 && i < len; i += step) {
      Component c = getItem(i);
      if (c instanceof Item) {
        Item item = (Item) c;
        if (item.canActivate && item.isEnabled()) {
          setActiveItem(item, false);
          return item;
        }
      }
    }
    return null;
  }

  private void clearGroups() {
    NodeList<Element> groups = el().select(".x-menu-radio-group");
    for (int i = 0; i < groups.getLength(); i++) {
      Element e = groups.getItem(i);
      El.fly(e).removeFromParent();
    }
  }

  private El getGroup(String groupName) {
    El g = el().selectNode("#" + getId() + "-" + groupName);
    if (g == null) {
      g = new El(DOM.createDiv());
      g.makePositionable(true);
      g.dom.setAttribute("role", "group");
      g.addStyleName(HideMode.OFFSETS.value());
      g.addStyleName("x-menu-radio-group");
      g.setId(getId() + "-" + groupName);
      el().appendChild(g.dom);
    }
    return g;
  }

  private void handleRadioGroups() {
    clearGroups();
    for (int i = 0; i < getItemCount(); i++) {
      Object obj = getItem(i);
      if (obj instanceof CheckMenuItem) {
        CheckMenuItem check = (CheckMenuItem) obj;
        if (check.getGroup() != null) {
          El g = getGroup(check.getGroup());
          Accessibility.setState(g.dom, "aria-owns", g.dom.getAttribute("aria-owns") + " " + check.getId());
          if (check.getAriaGroupTitle() != null) {
            g.dom.setTitle(check.getAriaGroupTitle());
          }
        }
      }
    }
  }
}
TOP

Related Classes of com.extjs.gxt.ui.client.widget.menu.Menu

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.