diff options
author | Jonas Zipprick <jonas.zipprick@gmail.com> | 2017-12-29 11:36:05 +0100 |
---|---|---|
committer | Aleksi Hietanen <aleksi@vaadin.com> | 2017-12-29 12:36:05 +0200 |
commit | 0663acc47174bf86c02cdb7291e1c0d7b98551ed (patch) | |
tree | 2c3076f2a1b2d376575555b7eb2a8aee7a5ce893 | |
parent | 1619d1f0bbd41de3f175b9eb2f34b468ec7e0367 (diff) | |
download | vaadin-framework-0663acc47174bf86c02cdb7291e1c0d7b98551ed.tar.gz vaadin-framework-0663acc47174bf86c02cdb7291e1c0d7b98551ed.zip |
Add ContentMode for the description of MenuItems (#9984)
Adds the ability to set the content mode for the description of a menu item that is part of a menu bar.
This functionality was already available for every AbstractComponent but missing for the menu items of menu bars.
If no content mode is specified it defaults to the PREFORMATED content mode.
6 files changed, 129 insertions, 10 deletions
diff --git a/client/src/main/java/com/vaadin/client/ui/VMenuBar.java b/client/src/main/java/com/vaadin/client/ui/VMenuBar.java index 29897f7dd6..144f6117d0 100644 --- a/client/src/main/java/com/vaadin/client/ui/VMenuBar.java +++ b/client/src/main/java/com/vaadin/client/ui/VMenuBar.java @@ -805,6 +805,7 @@ public class VMenuBar extends FocusableFlowPanel protected boolean checked = false; protected boolean selected = false; protected String description = null; + protected ContentMode contentMode = null; private String styleName; @@ -1114,15 +1115,24 @@ public class VMenuBar extends FocusableFlowPanel MenuBarConstants.ATTRIBUTE_ITEM_DESCRIPTION); } + if (uidl.hasAttribute( + MenuBarConstants.ATTRIBUTE_ITEM_CONTENT_MODE)) { + String contentModeString = uidl.getStringAttribute( + MenuBarConstants.ATTRIBUTE_ITEM_CONTENT_MODE); + contentMode = ContentMode.valueOf(contentModeString); + } else { + contentMode = ContentMode.PREFORMATTED; + } + updateStyleNames(); } public TooltipInfo getTooltip() { - if (description == null) { + if (description == null || contentMode == null) { return null; } - return new TooltipInfo(description, ContentMode.PREFORMATTED, null, + return new TooltipInfo(description, contentMode, null, this); } diff --git a/server/src/main/java/com/vaadin/ui/MenuBar.java b/server/src/main/java/com/vaadin/ui/MenuBar.java index 544b93ea6a..72a3671d4e 100644 --- a/server/src/main/java/com/vaadin/ui/MenuBar.java +++ b/server/src/main/java/com/vaadin/ui/MenuBar.java @@ -31,6 +31,7 @@ import org.jsoup.parser.Tag; import com.vaadin.server.PaintException; import com.vaadin.server.PaintTarget; import com.vaadin.server.Resource; +import com.vaadin.shared.ui.ContentMode; import com.vaadin.shared.ui.menubar.MenuBarConstants; import com.vaadin.shared.ui.menubar.MenuBarState; import com.vaadin.ui.Component.Focusable; @@ -142,6 +143,14 @@ public class MenuBar extends AbstractComponent target.addAttribute(MenuBarConstants.ATTRIBUTE_ITEM_DESCRIPTION, description); } + + ContentMode contentMode = item.getContentMode(); + // If the contentMode is equal to ContentMode.PREFORMATTED, we don't add any attribute. + if (contentMode != null && contentMode != ContentMode.PREFORMATTED) { + target.addAttribute(MenuBarConstants.ATTRIBUTE_ITEM_CONTENT_MODE, + contentMode.name()); + } + if (item.isCheckable()) { // if the "checked" attribute is present (either true or false), // the item is checkable @@ -457,6 +466,7 @@ public class MenuBar extends AbstractComponent private boolean isSeparator = false; private String styleName; private String description; + private ContentMode contentMode = ContentMode.PREFORMATTED; private boolean checkable = false; private boolean checked = false; @@ -782,20 +792,46 @@ public class MenuBar extends AbstractComponent } /** - * Sets the items's description. See {@link #getDescription()} for more + * Analogous method to {@link AbstractComponent#setDescription(String)}. + * Sets the item's description. See {@link #getDescription()} for more * information on what the description is. * * @param description * the new description string for the component. */ public void setDescription(String description) { + setDescription(description, ContentMode.PREFORMATTED); + } + + /** + * Analogous method to + * {@link AbstractComponent#setDescription(String, ContentMode)}. Sets + * the item's description using given content mode. See + * {@link #getDescription()} for more information on what the + * description is. + * <p> + * If the content {@code mode} is {@literal ContentMode.HTML} the + * description is displayed as HTML in tooltips or directly in certain + * components so care should be taken to avoid creating the possibility + * for HTML injection and possibly XSS vulnerabilities. + * + * @see ContentMode + * + * @param description + * the new description string for the component. + * @param mode + * the content mode for the description + * @since + */ + public void setDescription(String description, ContentMode mode) { this.description = description; + this.contentMode = mode; markAsDirty(); } /** * <p> - * Gets the items's description. The description can be used to briefly + * Gets the item's description. The description can be used to briefly * describe the state of the item to the user. The description string * may contain certain XML tags: * </p> @@ -854,6 +890,23 @@ public class MenuBar extends AbstractComponent } /** + * Gets the content mode of the description of the menu item. The + * description is displayed as the tooltip of the menu item in the UI. + * <p> + * If no content mode was explicitly set using the + * {@link #setDescription(String, ContentMode)} method, the content mode + * will be {@link ContentMode#PREFORMATTED} + * </p> + * + * @return the {@link ContentMode} of the description of this menu item + * @see ContentMode + * @since + */ + public ContentMode getContentMode() { + return contentMode; + } + + /** * Gets the checkable state of the item - whether the item has checked * and unchecked states. If an item is checkable its checked state (as * returned by {@link #isChecked()}) is indicated in the UI. @@ -982,6 +1035,9 @@ public class MenuBar extends AbstractComponent DesignAttributeHandler.writeAttribute("description", attr, item.getDescription(), def.getDescription(), String.class, context); + DesignAttributeHandler.writeAttribute("contentmode", attr, + item.getContentMode().name(), def.getContentMode().name(), String.class, + context); DesignAttributeHandler.writeAttribute("style-name", attr, item.getStyleName(), def.getStyleName(), String.class, context); @@ -1041,8 +1097,13 @@ public class MenuBar extends AbstractComponent attr, boolean.class)); } if (menuElement.hasAttr("description")) { - menu.setDescription(DesignAttributeHandler - .readAttribute("description", attr, String.class)); + String description = DesignAttributeHandler.readAttribute("description", attr, String.class); + if (menuElement.hasAttr("contentmode")) { + String contentModeString = DesignAttributeHandler.readAttribute("contentmode", attr, String.class); + menu.setDescription(description, ContentMode.valueOf(contentModeString)); + } else { + menu.setDescription(description); + } } if (menuElement.hasAttr("style-name")) { menu.setStyleName(DesignAttributeHandler.readAttribute("style-name", diff --git a/server/src/test/java/com/vaadin/tests/components/menubar/MenuBarDeclarativeTest.java b/server/src/test/java/com/vaadin/tests/components/menubar/MenuBarDeclarativeTest.java index 5a67d2bcce..68f1fad864 100644 --- a/server/src/test/java/com/vaadin/tests/components/menubar/MenuBarDeclarativeTest.java +++ b/server/src/test/java/com/vaadin/tests/components/menubar/MenuBarDeclarativeTest.java @@ -28,6 +28,7 @@ import com.vaadin.server.ThemeResource; import com.vaadin.tests.design.DeclarativeTestBase; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; +import com.vaadin.shared.ui.ContentMode; /** * Tests declarative support for menu bars. @@ -69,6 +70,27 @@ public class MenuBarDeclarativeTest extends DeclarativeTestBase<MenuBar> { } @Test + public void testDescriptionContentMode() { + String design = "<vaadin-menu-bar plain-text>" + + "<menu description=\"This description is implicitly preformatted\">One</menu>" + + "<menu description=\"This description\nis explicitly\n\npreformatted\">preformatted</menu>" + + "<menu contentmode=\"HTML\" description=\"<b>I</b> contain <br/> <e>html</e>\">HTML</menu>" + + "<menu contentmode=\"TEXT\" description=\"Just plain text\">plain text</menu>" + + "</vaadin-menu-bar>"; + MenuBar menuBar = new MenuBar(); + menuBar.addItem("One", null).setDescription("This description is implicitly preformatted"); + menuBar.addItem("preformatted", null) + .setDescription("This description\nis explicitly\n\npreformatted", ContentMode.PREFORMATTED); + menuBar.addItem("HTML", null) + .setDescription("<b>I</b> contain <br/> <e>html</e>", ContentMode.HTML); + menuBar.addItem("plain text", null) + .setDescription("Just plain text", ContentMode.TEXT); + + testWrite(design, menuBar); + testRead(design, menuBar); + } + + @Test // #16328 public void testTicketSpec1() throws IOException { String design = "<vaadin-menu-bar auto-open plain-text tabindex=5> " @@ -165,12 +187,13 @@ public class MenuBarDeclarativeTest extends DeclarativeTestBase<MenuBar> { actual.isSeparator()); assertEquals(baseError + "Enabled", expected.isEnabled(), actual.isEnabled()); - assertEquals(baseError + "Text", expected.getText(), actual.getText()); assertEquals(baseError + "Description", expected.getDescription(), actual.getDescription()); assertEquals(baseError + "Style Name", expected.getStyleName(), actual.getStyleName()); + assertEquals(baseError + "Content Mode", expected.getContentMode(), + actual.getContentMode()); if (expected.getIcon() != null) { assertNotNull(baseError + "Icon was null", actual.getIcon()); diff --git a/shared/src/main/java/com/vaadin/shared/ui/menubar/MenuBarConstants.java b/shared/src/main/java/com/vaadin/shared/ui/menubar/MenuBarConstants.java index 2d211824e6..4f5fcb72ff 100644 --- a/shared/src/main/java/com/vaadin/shared/ui/menubar/MenuBarConstants.java +++ b/shared/src/main/java/com/vaadin/shared/ui/menubar/MenuBarConstants.java @@ -24,6 +24,8 @@ public class MenuBarConstants implements Serializable { @Deprecated public static final String ATTRIBUTE_ITEM_DESCRIPTION = "description"; @Deprecated + public static final String ATTRIBUTE_ITEM_CONTENT_MODE = "contentmode"; + @Deprecated public static final String ATTRIBUTE_ITEM_ICON = "icon"; @Deprecated public static final String ATTRIBUTE_ITEM_DISABLED = "disabled"; diff --git a/uitest/src/main/java/com/vaadin/tests/elements/menubar/MenuBarUI.java b/uitest/src/main/java/com/vaadin/tests/elements/menubar/MenuBarUI.java index a78eae271c..d56ead71e9 100644 --- a/uitest/src/main/java/com/vaadin/tests/elements/menubar/MenuBarUI.java +++ b/uitest/src/main/java/com/vaadin/tests/elements/menubar/MenuBarUI.java @@ -16,6 +16,7 @@ package com.vaadin.tests.elements.menubar; import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.ContentMode; import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.Command; @@ -38,8 +39,11 @@ public class MenuBarUI extends AbstractTestUI { String secondaryLevelItemSuffix) { MenuBar menuBar = new MenuBar(); MenuItem file = menuBar.addItem("File" + topLevelItemSuffix, null); - file.addItem("Open" + secondaryLevelItemSuffix, new MenuBarCommand()); - file.addItem("Save" + secondaryLevelItemSuffix, new MenuBarCommand()); + file.addItem("Open" + secondaryLevelItemSuffix, new MenuBarCommand()) + .setDescription("<b>Preformatted</b>\ndescription"); + file.addItem("Save" + secondaryLevelItemSuffix, new MenuBarCommand()) + .setDescription("plain description,\n <b>HTML</b> is visible", + ContentMode.TEXT); file.addItem("Save As.." + secondaryLevelItemSuffix, new MenuBarCommand()); file.addSeparator(); @@ -52,7 +56,9 @@ public class MenuBarUI extends AbstractTestUI { new MenuBarCommand()); file.addSeparator(); - file.addItem("Exit" + secondaryLevelItemSuffix, new MenuBarCommand()); + file.addItem("Exit" + secondaryLevelItemSuffix, new MenuBarCommand()) + .setDescription("<b>HTML</b><br/>description", + ContentMode.HTML); MenuItem edit = menuBar.addItem("Edit" + topLevelItemSuffix, null); edit.addItem("Copy" + secondaryLevelItemSuffix, new MenuBarCommand()); diff --git a/uitest/src/test/java/com/vaadin/tests/elements/menubar/MenuBarUITest.java b/uitest/src/test/java/com/vaadin/tests/elements/menubar/MenuBarUITest.java index dc960f4d49..0fd42421a9 100644 --- a/uitest/src/test/java/com/vaadin/tests/elements/menubar/MenuBarUITest.java +++ b/uitest/src/test/java/com/vaadin/tests/elements/menubar/MenuBarUITest.java @@ -15,6 +15,7 @@ */ package com.vaadin.tests.elements.menubar; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -121,6 +122,22 @@ public class MenuBarUITest extends MultiBrowserTest { assertTrue(isItemVisible("Open")); } + @Test + public void testMenuItemTooltips() { + MenuBarElement first = $(MenuBarElement.class).first(); + first.clickItem("File"); + assertTooltip("Open", "<b>Preformatted</b>\ndescription"); + assertTooltip("Save", "plain description, <b>HTML</b> is visible"); + assertTooltip("Exit", "HTML\ndescription"); + } + + private void assertTooltip(String menuItem, String expectedTooltipText) { + testBenchElement(getMenuElement(menuItem)).showTooltip(); + assertEquals("Unexpected tooltip when hovering '" + menuItem + "'", + expectedTooltipText, + findElement(By.className("v-tooltip-text")).getText()); + } + private boolean isItemVisible(String item) { for (WebElement webElement : getItemCaptions()) { try { |