Change-Id: Ia2fce4dbfc205b44622557017afff19c4a2ef7dftags/7.5.0.alpha1
@@ -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; | |||
@@ -388,7 +378,8 @@ public class VTooltip extends VOverlay { | |||
} | |||
private class TooltipEventHandler implements MouseMoveHandler, | |||
KeyDownHandler, FocusHandler, BlurHandler, MouseDownHandler { | |||
KeyDownHandler, FocusHandler, BlurHandler, MouseDownHandler, | |||
MouseUpHandler, TouchStartHandler { | |||
/** | |||
* Current element hovered | |||
@@ -400,6 +391,11 @@ public class VTooltip extends VOverlay { | |||
*/ | |||
private boolean handledByFocus; | |||
/** | |||
* Indicates whether the tooltip is being called after a touch event. | |||
*/ | |||
private boolean touchInitiated = false; | |||
/** | |||
* Locate the tooltip for given element | |||
* | |||
@@ -450,7 +446,19 @@ public class VTooltip extends VOverlay { | |||
@Override | |||
public void onMouseMove(MouseMoveEvent mme) { | |||
handleShowHide(mme, false); | |||
if (!touchInitiated) { | |||
handleShowHide(mme, false); | |||
} | |||
} | |||
@Override | |||
public void onMouseUp(MouseUpEvent event) { | |||
touchInitiated = false; | |||
} | |||
@Override | |||
public void onTouchStart(TouchStartEvent te) { | |||
touchInitiated = true; | |||
} | |||
@Override | |||
@@ -550,9 +558,11 @@ public class VTooltip extends VOverlay { | |||
Profiler.enter("VTooltip.connectHandlersToWidget"); | |||
widget.addDomHandler(tooltipEventHandler, MouseMoveEvent.getType()); | |||
widget.addDomHandler(tooltipEventHandler, MouseDownEvent.getType()); | |||
widget.addDomHandler(tooltipEventHandler, MouseUpEvent.getType()); | |||
widget.addDomHandler(tooltipEventHandler, KeyDownEvent.getType()); | |||
widget.addDomHandler(tooltipEventHandler, FocusEvent.getType()); | |||
widget.addDomHandler(tooltipEventHandler, BlurEvent.getType()); | |||
widget.addDomHandler(tooltipEventHandler, TouchStartEvent.getType()); | |||
Profiler.leave("VTooltip.connectHandlersToWidget"); | |||
} | |||
@@ -22,9 +22,12 @@ import com.google.gwt.aria.client.Roles; | |||
import com.google.gwt.core.client.GWT; | |||
import com.google.gwt.dom.client.Document; | |||
import com.google.gwt.dom.client.Element; | |||
import com.google.gwt.user.client.DOM; | |||
import com.google.gwt.user.client.Event; | |||
import com.google.gwt.user.client.Timer; | |||
import com.google.gwt.event.dom.client.BlurEvent; | |||
import com.google.gwt.event.dom.client.BlurHandler; | |||
import com.google.gwt.event.dom.client.FocusEvent; | |||
import com.google.gwt.event.dom.client.FocusHandler; | |||
import com.google.gwt.event.shared.HandlerRegistration; | |||
import com.google.gwt.user.client.*; | |||
import com.google.gwt.user.client.ui.SimplePanel; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.vaadin.client.BrowserInfo; | |||
@@ -44,6 +47,7 @@ import com.vaadin.shared.ui.AlignmentInfo; | |||
public final class Slot extends SimplePanel { | |||
private static final String ALIGN_CLASS_PREFIX = "v-align-"; | |||
private static final int TOUCH_ERROR_MESSAGE_HIDE_DELAY = 200; | |||
private final VAbstractOrderedLayout layout; | |||
@@ -55,8 +59,13 @@ public final class Slot extends SimplePanel { | |||
private Element captionText; | |||
private Icon icon; | |||
private Element errorIcon; | |||
private Element errorMessage; | |||
private Element requiredIcon; | |||
private HandlerRegistration focusRegistration; | |||
private HandlerRegistration blurRegistration; | |||
private boolean labelClicked = false; | |||
private ElementResizeListener captionResizeListener; | |||
private ElementResizeListener widgetResizeListener; | |||
@@ -582,9 +591,21 @@ public final class Slot extends SimplePanel { | |||
errorIcon.setClassName("v-errorindicator"); | |||
} | |||
caption.appendChild(errorIcon); | |||
} else if (errorIcon != null) { | |||
errorIcon.removeFromParent(); | |||
errorIcon = null; | |||
if(BrowserInfo.get().isTouchDevice()) { | |||
addFocusHandlerToWidget(error, widget); | |||
addBlurHandlerToWidget(widget); | |||
} | |||
} else { | |||
if (errorIcon != null) { | |||
errorIcon.removeFromParent(); | |||
errorIcon = null; | |||
} | |||
if (errorMessage != null) { | |||
removeErrorMessageAndHandlers(); | |||
} | |||
} | |||
if (caption != null) { | |||
@@ -651,6 +672,81 @@ public final class Slot extends SimplePanel { | |||
} | |||
} | |||
private void removeErrorMessageAndHandlers() { | |||
errorMessage.removeFromParent(); | |||
errorMessage = null; | |||
if (focusRegistration != null) { | |||
focusRegistration.removeHandler(); | |||
focusRegistration = null; | |||
} | |||
if(blurRegistration != null) { | |||
blurRegistration.removeHandler(); | |||
blurRegistration = null; | |||
} | |||
} | |||
private void addFocusHandlerToWidget(final String error, Widget widget) { | |||
focusRegistration = widget.addHandler(new FocusHandler() { | |||
@Override | |||
public void onFocus(FocusEvent event) { | |||
if(labelClicked) { | |||
labelClicked = false; | |||
return; | |||
} | |||
if (errorMessage == null) { | |||
errorMessage = DOM.createDiv(); | |||
errorMessage.setClassName("v-touch-error-message"); | |||
} | |||
errorMessage.setInnerHTML(error); | |||
captionWrap.appendChild(errorMessage); | |||
} | |||
}, FocusEvent.getType()); | |||
} | |||
private void addBlurHandlerToWidget(final Widget widget) { | |||
blurRegistration = widget.addHandler(new BlurHandler() { | |||
@Override | |||
public void onBlur(BlurEvent event) { | |||
if(errorMessage != null) { | |||
addClickHandlerToErrorMessage(widget); | |||
} | |||
scheduleErrorMessageHide(TOUCH_ERROR_MESSAGE_HIDE_DELAY); | |||
} | |||
}, BlurEvent.getType()); | |||
} | |||
private void scheduleErrorMessageHide(int delay) { | |||
//Delaying hiding to allow error message click handler | |||
//do his job and return the focus back if error message was tapped | |||
Timer hideTimer = new Timer() { | |||
@Override | |||
public void run() { | |||
if(errorMessage != null) { | |||
errorMessage.removeFromParent(); | |||
errorMessage = null; | |||
} | |||
} | |||
}; | |||
hideTimer.schedule(delay); | |||
} | |||
private void addClickHandlerToErrorMessage(final Widget widget) { | |||
Event.sinkEvents(errorMessage, Event.ONCLICK); | |||
Event.setEventListener(errorMessage, new EventListener() { | |||
@Override | |||
public void onBrowserEvent(Event event) { | |||
if(Event.ONCLICK == event.getTypeInt()) { | |||
errorMessage.removeFromParent(); | |||
errorMessage = null; | |||
labelClicked = true; | |||
widget.getElement().focus(); | |||
} | |||
} | |||
}); | |||
} | |||
/** | |||
* Does the slot have a caption | |||
*/ |
@@ -0,0 +1,57 @@ | |||
package com.vaadin.tests.components; | |||
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; | |||
public class TouchDevicesTooltip extends AbstractTestUI { | |||
@Override | |||
protected void setup(VaadinRequest request) { | |||
final Label errorLabel = new Label("No error"); | |||
addComponent(errorLabel); | |||
TextField textField = new TextField("Value"); | |||
textField.setConverter(new StringToIntegerConverter()); | |||
textField.addValidator(new IntegerRangeValidator("incorrect value", 0, 100)); | |||
textField.setImmediate(true); | |||
textField.setValue("-5"); | |||
addComponent(textField); | |||
TextField textField2 = new TextField("Value2"); | |||
textField2.setConverter(new StringToIntegerConverter()); | |||
textField2.addValidator(new IntegerRangeValidator("incorrect value2", 0, 100)); | |||
textField2.setImmediate(true); | |||
textField2.setValue("-5"); | |||
addComponent(textField2); | |||
} | |||
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 15353; | |||
} | |||
@Override | |||
public String getDescription() { | |||
return "Displaying error message in slot for touch devices"; | |||
} | |||
} |