Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

MenuBarConnector.java 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. * Copyright 2000-2021 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client.ui.menubar;
  17. import java.util.Iterator;
  18. import java.util.Stack;
  19. import com.google.gwt.core.client.GWT;
  20. import com.google.gwt.dom.client.Element;
  21. import com.google.gwt.user.client.Command;
  22. import com.google.gwt.user.client.Timer;
  23. import com.vaadin.client.ApplicationConnection;
  24. import com.vaadin.client.BrowserInfo;
  25. import com.vaadin.client.Paintable;
  26. import com.vaadin.client.TooltipInfo;
  27. import com.vaadin.client.UIDL;
  28. import com.vaadin.client.annotations.OnStateChange;
  29. import com.vaadin.client.ui.AbstractComponentConnector;
  30. import com.vaadin.client.ui.Icon;
  31. import com.vaadin.client.ui.SimpleManagedLayout;
  32. import com.vaadin.client.ui.VMenuBar;
  33. import com.vaadin.shared.ui.ComponentStateUtil;
  34. import com.vaadin.shared.ui.Connect;
  35. import com.vaadin.shared.ui.menubar.MenuBarConstants;
  36. import com.vaadin.shared.ui.menubar.MenuBarState;
  37. /**
  38. * A connector class for the MenuBar component.
  39. *
  40. * @author Vaadin Ltd
  41. */
  42. @SuppressWarnings("deprecation")
  43. @Connect(com.vaadin.ui.MenuBar.class)
  44. public class MenuBarConnector extends AbstractComponentConnector
  45. implements Paintable, SimpleManagedLayout {
  46. /**
  47. * This method must be implemented to update the client-side component from
  48. * UIDL data received from server.
  49. *
  50. * This method is called when the page is loaded for the first time, and
  51. * every time UI changes in the component are received from the server.
  52. */
  53. @Override
  54. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  55. if (!isRealUpdate(uidl)) {
  56. return;
  57. }
  58. VMenuBar widget = getWidget();
  59. widget.htmlContentAllowed = uidl
  60. .hasAttribute(MenuBarConstants.HTML_CONTENT_ALLOWED);
  61. if (BrowserInfo.get().isAndroid() || BrowserInfo.get().isIOS()) {
  62. // disable the auto-open on hover on devices that don't support
  63. // hover.
  64. // fixes https://github.com/vaadin/framework/issues/5873
  65. widget.openRootOnHover = false;
  66. } else {
  67. widget.openRootOnHover = uidl.getBooleanAttribute(
  68. MenuBarConstants.OPEN_ROOT_MENU_ON_HOWER);
  69. }
  70. widget.enabled = isEnabled();
  71. // For future connections
  72. widget.client = client;
  73. widget.uidlId = uidl.getId();
  74. Timer timer = new Timer() {
  75. @Override
  76. public void run() {
  77. // Empty the menu every time it receives new information
  78. if (!widget.getItems().isEmpty()) {
  79. widget.clearItems();
  80. }
  81. UIDL options = uidl.getChildUIDL(0);
  82. if (null != getState()
  83. && !ComponentStateUtil.isUndefinedWidth(getState())) {
  84. UIDL moreItemUIDL = options.getChildUIDL(0);
  85. StringBuilder itemHTML = new StringBuilder();
  86. if (moreItemUIDL.hasAttribute("icon")) {
  87. Icon icon = client.getIcon(
  88. moreItemUIDL.getStringAttribute("icon"));
  89. if (icon != null) {
  90. itemHTML.append(icon.getElement().getString());
  91. }
  92. }
  93. String moreItemText = moreItemUIDL
  94. .getStringAttribute("text");
  95. if ("".equals(moreItemText)) {
  96. moreItemText = "►";
  97. }
  98. itemHTML.append(moreItemText);
  99. widget.moreItem = GWT.create(VMenuBar.CustomMenuItem.class);
  100. widget.moreItem.setHTML(itemHTML.toString());
  101. widget.moreItem.setCommand(VMenuBar.emptyCommand);
  102. widget.collapsedRootItems = new VMenuBar(true, widget);
  103. widget.moreItem.setSubMenu(widget.collapsedRootItems);
  104. widget.moreItem.addStyleName(
  105. widget.getStylePrimaryName() + "-more-menuitem");
  106. }
  107. UIDL uidlItems = uidl.getChildUIDL(1);
  108. Iterator<Object> itr = uidlItems.iterator();
  109. Stack<Iterator<Object>> iteratorStack = new Stack<>();
  110. Stack<VMenuBar> menuStack = new Stack<>();
  111. VMenuBar currentMenu = widget;
  112. while (itr.hasNext()) {
  113. UIDL item = (UIDL) itr.next();
  114. VMenuBar.CustomMenuItem currentItem = null;
  115. final int itemId = item.getIntAttribute("id");
  116. boolean itemHasCommand = item.hasAttribute("command");
  117. boolean itemIsCheckable = item
  118. .hasAttribute(MenuBarConstants.ATTRIBUTE_CHECKED);
  119. String itemHTML = widget.buildItemHTML(item);
  120. Command cmd = null;
  121. if (!item.hasAttribute("separator")) {
  122. if (itemHasCommand || itemIsCheckable) {
  123. // Construct a command that fires onMenuClick(int)
  124. // with the
  125. // item's id-number
  126. cmd = () -> widget.hostReference
  127. .onMenuClick(itemId);
  128. }
  129. }
  130. currentItem = currentMenu.addItem(itemHTML, cmd);
  131. currentItem.setId("" + itemId);
  132. currentItem.updateFromUIDL(item, client);
  133. String domId = getState().id;
  134. if (domId != null && !domId.isEmpty()) {
  135. currentItem.getElement().setId(domId + "-" + itemId);
  136. }
  137. if (item.getChildCount() > 0) {
  138. menuStack.push(currentMenu);
  139. iteratorStack.push(itr);
  140. itr = item.iterator();
  141. currentMenu = new VMenuBar(true, currentMenu);
  142. client.getVTooltip()
  143. .connectHandlersToWidget(currentMenu);
  144. // this is the top-level style that also propagates to
  145. // items -
  146. // any item specific styles are set above in
  147. // currentItem.updateFromUIDL(item, client)
  148. if (ComponentStateUtil.hasStyles(getState())) {
  149. for (String style : getState().styles) {
  150. currentMenu.addStyleDependentName(style);
  151. }
  152. }
  153. currentItem.setSubMenu(currentMenu);
  154. }
  155. while (!itr.hasNext() && !iteratorStack.empty()) {
  156. boolean hasCheckableItem = false;
  157. for (VMenuBar.CustomMenuItem menuItem : currentMenu
  158. .getItems()) {
  159. hasCheckableItem = hasCheckableItem
  160. || menuItem.isCheckable();
  161. }
  162. if (hasCheckableItem) {
  163. currentMenu.addStyleDependentName("check-column");
  164. } else {
  165. currentMenu
  166. .removeStyleDependentName("check-column");
  167. }
  168. itr = iteratorStack.pop();
  169. currentMenu = menuStack.pop();
  170. }
  171. }
  172. }
  173. };
  174. getLayoutManager().setNeedsHorizontalLayout(MenuBarConnector.this);
  175. if (widget.mouseDownPressed) {
  176. timer.schedule(getState().delayMs);
  177. widget.mouseDownPressed = false;
  178. } else {
  179. timer.run();
  180. }
  181. }
  182. @Override
  183. public VMenuBar getWidget() {
  184. return (VMenuBar) super.getWidget();
  185. }
  186. @Override
  187. public MenuBarState getState() {
  188. return (MenuBarState) super.getState();
  189. }
  190. @Override
  191. public void layout() {
  192. getWidget().iLayout();
  193. }
  194. @Override
  195. public TooltipInfo getTooltipInfo(Element element) {
  196. TooltipInfo info = null;
  197. // Check content of widget to find tooltip for element
  198. if (element != getWidget().getElement()) {
  199. VMenuBar.CustomMenuItem item = getWidget()
  200. .getMenuItemWithElement(element);
  201. if (item != null) {
  202. info = item.getTooltip();
  203. }
  204. }
  205. // Use default tooltip if nothing found from DOM three
  206. if (info == null) {
  207. info = super.getTooltipInfo(element);
  208. }
  209. return info;
  210. }
  211. @Override
  212. public boolean hasTooltip() {
  213. /*
  214. * Item tooltips are not processed until updateFromUIDL, so we can't be
  215. * sure that there are no tooltips during onStateChange when this method
  216. * is used.
  217. */
  218. return true;
  219. }
  220. @OnStateChange("enabled")
  221. void updateEnabled() {
  222. if (getState().enabled) {
  223. getWidget().getElement().removeAttribute("aria-disabled");
  224. } else {
  225. getWidget().getElement().setAttribute("aria-disabled", "true");
  226. }
  227. }
  228. @OnStateChange("tabIndex")
  229. void updateTabIndex() {
  230. getWidget().getElement().setAttribute("tabindex",
  231. String.valueOf(getState().tabIndex));
  232. }
  233. }