From b0678ebbcc5e238f9bce3f6aac0d8c70c9e25178 Mon Sep 17 00:00:00 2001 From: Juuso Valli Date: Mon, 2 Jun 2014 18:46:07 +0300 Subject: [PATCH] Fix tooltip positioning near screen edges (#12870) Change-Id: I3f5244565dd393e9fcb7386d352f835b5afd9faa --- client/src/com/vaadin/client/VTooltip.java | 53 +++++++++- .../menubar/MenuBarTooltipsNearEdge.java | 96 +++++++++++++++++++ .../menubar/MenuBarTooltipsNearEdgeTest.java | 69 +++++++++++++ 3 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdge.java create mode 100644 uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdgeTest.java diff --git a/client/src/com/vaadin/client/VTooltip.java b/client/src/com/vaadin/client/VTooltip.java index bbf5e5c32c..77720089b1 100644 --- a/client/src/com/vaadin/client/VTooltip.java +++ b/client/src/com/vaadin/client/VTooltip.java @@ -153,15 +153,61 @@ public class VTooltip extends VWindowOverlay { offsetWidth = getOffsetWidth(); offsetHeight = getOffsetHeight(); } + int x = getFinalX(offsetWidth); + int y = getFinalY(offsetHeight); - int x = tooltipEventMouseX + 10 + Window.getScrollLeft(); - int y = tooltipEventMouseY + 10 + Window.getScrollTop(); + setPopupPosition(x, y); + sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT); + } + /** + * Return the final X-coordinate of the tooltip based on cursor + * position, size of the tooltip, size of the page and necessary + * margins. + * + * @param offsetWidth + * @return The final X-coordinate + */ + private int getFinalX(int offsetWidth) { + int x = 0; + int widthNeeded = 10 + MARGIN + offsetWidth; + int roomLeft = tooltipEventMouseX; + int roomRight = Window.getClientWidth() - roomLeft; + if (roomRight > widthNeeded) { + x = tooltipEventMouseX + 10 + Window.getScrollLeft(); + } else { + x = tooltipEventMouseX + Window.getScrollLeft() - 10 + - offsetWidth; + } if (x + offsetWidth + MARGIN - Window.getScrollLeft() > Window .getClientWidth()) { x = Window.getClientWidth() - offsetWidth - MARGIN + Window.getScrollLeft(); } + return x; + } + + /** + * Return the final Y-coordinate of the tooltip based on cursor + * position, size of the tooltip, size of the page and necessary + * margins. + * + * @param offsetHeight + * @return The final y-coordinate + * + */ + private int getFinalY(int offsetHeight) { + int y = 0; + int heightNeeded = 10 + MARGIN + offsetHeight; + int roomAbove = tooltipEventMouseY; + int roomBelow = Window.getClientHeight() - roomAbove; + + if (roomBelow > heightNeeded) { + y = tooltipEventMouseY + 10 + Window.getScrollTop(); + } else { + y = tooltipEventMouseY + Window.getScrollTop() - 10 + - offsetHeight; + } if (y + offsetHeight + MARGIN - Window.getScrollTop() > Window .getClientHeight()) { @@ -173,8 +219,7 @@ public class VTooltip extends VWindowOverlay { y = Window.getScrollTop(); } } - setPopupPosition(x, y); - sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT); + return y; } }); } else { diff --git a/uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdge.java b/uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdge.java new file mode 100644 index 0000000000..4e42d97925 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdge.java @@ -0,0 +1,96 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.menubar; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Component; +import com.vaadin.ui.MenuBar; +import com.vaadin.ui.MenuBar.Command; +import com.vaadin.ui.MenuBar.MenuItem; +import com.vaadin.ui.VerticalLayout; + +/** + * Test to see if tooltips will render in the correct locations near the edges. + * + * @author Vaadin Ltd + */ +public class MenuBarTooltipsNearEdge extends AbstractTestUI { + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server. + * VaadinRequest) + */ + @Override + protected void setup(VaadinRequest request) { + VerticalLayout vlayout = new VerticalLayout(); + vlayout.setSizeFull(); + vlayout.addComponent(buildMenu("Menu")); + vlayout.setComponentAlignment(vlayout.getComponent(0), + Alignment.BOTTOM_RIGHT); + setContent(vlayout); + + getTooltipConfiguration().setOpenDelay(0); + getTooltipConfiguration().setQuickOpenDelay(0); + getTooltipConfiguration().setCloseTimeout(1000); + + } + + private Component buildMenu(String label) { + MenuBar menu = new MenuBar(); + MenuItem item = menu.addItem(label, null); + + item.addItem("Item 1", null).setDescription("TOOLTIP 1"); + item.addItem("Item 2", null).setDescription("TOOLTIP 2"); + item.addItem("Item 3", null).setDescription("TOOLTIP 3"); + item.addItem("Item 4", null).setDescription("TOOLTIP 4"); + + return menu; + } + + private Command buildCommand() { + Command command = new Command() { + + @Override + public void menuSelected(MenuItem selectedItem) { + + } + }; + return command; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription() + */ + @Override + protected String getTestDescription() { + return "Menu item tooltips should not abscure other menu items"; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber() + */ + @Override + protected Integer getTicketNumber() { + return 12870; + } +} diff --git a/uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdgeTest.java b/uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdgeTest.java new file mode 100644 index 0000000000..197963a612 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/menubar/MenuBarTooltipsNearEdgeTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.menubar; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThan; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.HasInputDevices; +import org.openqa.selenium.interactions.Mouse; +import org.openqa.selenium.interactions.internal.Coordinates; +import org.openqa.selenium.internal.Locatable; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.MenuBarElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +/** + * Test to see if tooltips will render in the correct locations near the edges. + * + * @author Vaadin Ltd + */ +public class MenuBarTooltipsNearEdgeTest extends MultiBrowserTest { + + @Override + public List getBrowsersToTest() { + // Tooltip tests work unreliably on IE due to an issue with the + // WebDriver (see #13854) + List browsers = super.getBrowsersToTest(); + browsers.remove(Browser.IE8.getDesiredCapabilities()); + return browsers; + }; + + @Test + public void testTooltipLocation() { + openTestURL(); + Mouse mouse = ((HasInputDevices) getDriver()).getMouse(); + WebElement menu = $(MenuBarElement.class).first().getWrappedElement(); + Coordinates menuLocation = ((Locatable) menu).getCoordinates(); + mouse.click(menuLocation); + mouse.mouseMove(menuLocation, 5, -40); + WebElement tooltip = getTooltipElement(); + assertThat(tooltip.getLocation().x, is(lessThan(menuLocation.onPage().x + - tooltip.getSize().getWidth()))); + + } + + private WebElement getTooltipElement() { + return getDriver().findElement(By.className("v-tooltip-text")); + } +} -- 2.39.5