summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/com/vaadin/client/BrowserInfo.java3
-rw-r--r--client/src/com/vaadin/client/VTooltip.java127
-rw-r--r--client/src/com/vaadin/client/ui/VFormLayout.java6
-rw-r--r--shared/src/com/vaadin/shared/VBrowserDetails.java11
-rw-r--r--uitest/src/com/vaadin/tests/components/TouchDevicesTooltip.java66
5 files changed, 191 insertions, 22 deletions
diff --git a/client/src/com/vaadin/client/BrowserInfo.java b/client/src/com/vaadin/client/BrowserInfo.java
index 3bc75a9a9b..01968a17a6 100644
--- a/client/src/com/vaadin/client/BrowserInfo.java
+++ b/client/src/com/vaadin/client/BrowserInfo.java
@@ -88,7 +88,8 @@ public class BrowserInfo {
} else if (browserDetails.isIE()) {
touchDevice = detectIETouchDevice();
} else {
- touchDevice = detectTouchDevice();
+ //PhantomJS pretends to be a touch device which breaks some UI tests
+ touchDevice = !browserDetails.isPhantomJS() && detectTouchDevice();
}
}
diff --git a/client/src/com/vaadin/client/VTooltip.java b/client/src/com/vaadin/client/VTooltip.java
index 453563370c..b9392e3941 100644
--- a/client/src/com/vaadin/client/VTooltip.java
+++ b/client/src/com/vaadin/client/VTooltip.java
@@ -20,17 +20,7 @@ import com.google.gwt.aria.client.RelevantValue;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Display;
-import com.google.gwt.event.dom.client.BlurEvent;
-import com.google.gwt.event.dom.client.BlurHandler;
-import com.google.gwt.event.dom.client.DomEvent;
-import com.google.gwt.event.dom.client.FocusEvent;
-import com.google.gwt.event.dom.client.FocusHandler;
-import com.google.gwt.event.dom.client.KeyDownEvent;
-import com.google.gwt.event.dom.client.KeyDownHandler;
-import com.google.gwt.event.dom.client.MouseDownEvent;
-import com.google.gwt.event.dom.client.MouseDownHandler;
-import com.google.gwt.event.dom.client.MouseMoveEvent;
-import com.google.gwt.event.dom.client.MouseMoveHandler;
+import com.google.gwt.event.dom.client.*;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
@@ -70,6 +60,11 @@ public class VTooltip extends VOverlay {
private int closeTimeout;
/**
+ * Current element hovered
+ */
+ private com.google.gwt.dom.client.Element currentElement = null;
+
+ /**
* Used to show tooltips; usually used via the singleton in
* {@link ApplicationConnection}. NOTE that #setOwner(Widget)} should be
* called after instantiating.
@@ -179,8 +174,20 @@ public class VTooltip extends VOverlay {
offsetWidth = getOffsetWidth();
offsetHeight = getOffsetHeight();
}
- int x = getFinalX(offsetWidth);
- int y = getFinalY(offsetHeight);
+
+ int x = 0;
+ int y = 0;
+ if(BrowserInfo.get().isTouchDevice()) {
+ setMaxWidth(Window.getClientWidth());
+ offsetWidth = getOffsetWidth();
+ offsetHeight = getOffsetHeight();
+
+ x = getFinalTouchX(offsetWidth);
+ y = getFinalTouchY(offsetHeight);
+ } else {
+ x = getFinalX(offsetWidth);
+ y = getFinalY(offsetHeight);
+ }
setPopupPosition(x, y);
sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT);
@@ -222,6 +229,40 @@ public class VTooltip extends VOverlay {
}
/**
+ * 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 getFinalTouchX(int offsetWidth) {
+ int x = 0;
+ int widthNeeded = 10 + offsetWidth;
+ int roomLeft = currentElement != null ?
+ currentElement.getAbsoluteLeft() : EVENT_XY_POSITION_OUTSIDE;
+ int viewPortWidth = Window.getClientWidth();
+ int roomRight = viewPortWidth - roomLeft;
+ if (roomRight > widthNeeded) {
+ x = roomLeft;
+ } else {
+ x = roomLeft - offsetWidth;
+ }
+ if (x + offsetWidth - Window.getScrollLeft() > viewPortWidth) {
+ x = viewPortWidth - offsetWidth + Window.getScrollLeft();
+ }
+
+ if (roomLeft != EVENT_XY_POSITION_OUTSIDE) {
+ // Do not allow x to be zero, for otherwise the tooltip
+ // does not close when the mouse is moved (see
+ // isTooltipOpen()). #15129
+ int minX = Window.getScrollLeft();
+ x = Math.max(x, minX);
+ }
+ 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.
@@ -232,7 +273,7 @@ public class VTooltip extends VOverlay {
*/
private int getFinalY(int offsetHeight) {
int y = 0;
- int heightNeeded = 10 + MARGIN + offsetHeight;
+ int heightNeeded = 10 + offsetHeight;
int roomAbove = tooltipEventMouseY;
int roomBelow = Window.getClientHeight() - roomAbove;
@@ -263,12 +304,58 @@ public class VTooltip extends VOverlay {
}
return y;
}
+
+ /**
+ * 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 getFinalTouchY(int offsetHeight) {
+ int y = 0;
+ int heightNeeded = 10 + offsetHeight;
+ int roomAbove = currentElement != null ?
+ currentElement.getAbsoluteTop() + currentElement.getOffsetHeight()
+ : EVENT_XY_POSITION_OUTSIDE;
+ int roomBelow = Window.getClientHeight() - roomAbove;
+
+ if (roomBelow > heightNeeded) {
+ y = roomAbove;
+ } else {
+ y = roomAbove - offsetHeight -
+ (currentElement != null ? currentElement.getOffsetHeight() : 0);
+ }
+
+ if (y + offsetHeight - Window.getScrollTop() > Window
+ .getClientHeight()) {
+ y = roomAbove - 5 - offsetHeight
+ + Window.getScrollTop();
+ if (y - Window.getScrollTop() < 0) {
+ // tooltip does not fit on top of the mouse either,
+ // put it at the top of the screen
+ y = Window.getScrollTop();
+ }
+ }
+
+ if (roomAbove != EVENT_XY_POSITION_OUTSIDE) {
+ // Do not allow y to be zero, for otherwise the tooltip
+ // does not close when the mouse is moved (see
+ // isTooltipOpen()). #15129
+ int minY = Window.getScrollTop();
+ y = Math.max(y, minY);
+ }
+ return y;
+ }
});
} else {
hide();
}
}
+
/**
* For assistive tooltips to work correctly we must have the tooltip visible
* and attached to the DOM well in advance. For this reason both isShowing
@@ -391,11 +478,6 @@ public class VTooltip extends VOverlay {
KeyDownHandler, FocusHandler, BlurHandler, MouseDownHandler {
/**
- * Current element hovered
- */
- private com.google.gwt.dom.client.Element currentElement = null;
-
- /**
* Marker for handling of tooltip through focus
*/
private boolean handledByFocus;
@@ -455,7 +537,7 @@ public class VTooltip extends VOverlay {
@Override
public void onMouseDown(MouseDownEvent event) {
- handleHideEvent();
+ handleHideEvent();
}
@Override
@@ -524,6 +606,11 @@ public class VTooltip extends VOverlay {
updatePosition(event, isFocused);
// Schedule timer for showing the tooltip according to if it
// was recently closed or not.
+
+ if (BrowserInfo.get().isIOS()) {
+ element.focus();
+ }
+
int timeout = justClosed ? getQuickOpenDelay() : getOpenDelay();
if (timeout == 0) {
showTooltip();
diff --git a/client/src/com/vaadin/client/ui/VFormLayout.java b/client/src/com/vaadin/client/ui/VFormLayout.java
index a2ea77d31c..3781305e52 100644
--- a/client/src/com/vaadin/client/ui/VFormLayout.java
+++ b/client/src/com/vaadin/client/ui/VFormLayout.java
@@ -361,7 +361,11 @@ public class VFormLayout extends SimplePanel {
public ErrorFlag(ComponentConnector owner) {
setStyleName(CLASSNAME);
- sinkEvents(VTooltip.TOOLTIP_EVENTS);
+
+ if(!BrowserInfo.get().isTouchDevice()) {
+ sinkEvents(VTooltip.TOOLTIP_EVENTS);
+ }
+
this.owner = owner;
}
diff --git a/shared/src/com/vaadin/shared/VBrowserDetails.java b/shared/src/com/vaadin/shared/VBrowserDetails.java
index 6e45d33e16..561b6c76d0 100644
--- a/shared/src/com/vaadin/shared/VBrowserDetails.java
+++ b/shared/src/com/vaadin/shared/VBrowserDetails.java
@@ -41,6 +41,7 @@ public class VBrowserDetails implements Serializable {
private boolean isFirefox = false;
private boolean isOpera = false;
private boolean isIE = false;
+ private boolean isPhantomJS = false;
private boolean isWindowsPhone;
private boolean isIPad;
@@ -86,6 +87,7 @@ public class VBrowserDetails implements Serializable {
isSafari = !isChrome && !isIE && userAgent.indexOf("safari") != -1;
isFirefox = userAgent.indexOf(" firefox/") != -1;
+ isPhantomJS = userAgent.indexOf("phantomjs/") != -1;
// chromeframe
isChromeFrameCapable = userAgent.indexOf("chromeframe") != -1;
@@ -371,6 +373,15 @@ public class VBrowserDetails implements Serializable {
}
/**
+ * Tests if the browser is PhantomJS.
+ *
+ * @return true if it is PhantomJS, false otherwise
+ */
+ public boolean isPhantomJS() {
+ return isPhantomJS;
+ }
+
+ /**
* Returns the version of the browser engine. For WebKit this is an integer
* e.g., 532.0. For gecko it is a float e.g., 1.8 or 1.9.
*
diff --git a/uitest/src/com/vaadin/tests/components/TouchDevicesTooltip.java b/uitest/src/com/vaadin/tests/components/TouchDevicesTooltip.java
new file mode 100644
index 0000000000..ac4b48711e
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/TouchDevicesTooltip.java
@@ -0,0 +1,66 @@
+package com.vaadin.tests.components;
+
+import com.vaadin.annotations.Viewport;
+import com.vaadin.data.util.converter.StringToIntegerConverter;
+import com.vaadin.data.validator.IntegerRangeValidator;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+@Viewport(value = "width=device-width,height=device-height")
+public class TouchDevicesTooltip extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ final Label errorLabel = new Label("No error");
+ addComponent(errorLabel);
+
+ for (int i = 0; i < 50; i++) {
+ createTextField(i);
+ }
+ }
+
+ private void createTextField(int n) {
+ TextField textField = new TextField("Value" + n);
+ textField.setConverter(new StringToIntegerConverter());
+ textField.addValidator(new IntegerRangeValidator(getErrorMessage(n), 0, 100));
+ textField.setImmediate(true);
+ textField.setValue("-5");
+ addComponent(textField);
+ }
+
+ private String getErrorMessage(int n) {
+ if(n % 2 == 0) {
+ return "incorrect value" + n;
+ } else {
+ return "super long long long long long long long long long long long error message " + n;
+ }
+ }
+
+ public static class Bean {
+ @NotNull
+ @Min(0)
+ private Integer value;
+
+ public Integer getValue() {
+ return value;
+ }
+
+ public void setValue(Integer value) {
+ this.value = value;
+ }
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 17150;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Unable to dismiss a tooltip on touch devices";
+ }
+} \ No newline at end of file