Change-Id: Ia2fce4dbfc205b44622557017afff19c4a2ef7dftags/7.5.0.alpha1
import com.google.gwt.aria.client.Roles; | import com.google.gwt.aria.client.Roles; | ||||
import com.google.gwt.dom.client.Element; | import com.google.gwt.dom.client.Element; | ||||
import com.google.gwt.dom.client.Style.Display; | 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.DOM; | ||||
import com.google.gwt.user.client.Event; | import com.google.gwt.user.client.Event; | ||||
import com.google.gwt.user.client.Timer; | import com.google.gwt.user.client.Timer; | ||||
} | } | ||||
private class TooltipEventHandler implements MouseMoveHandler, | private class TooltipEventHandler implements MouseMoveHandler, | ||||
KeyDownHandler, FocusHandler, BlurHandler, MouseDownHandler { | |||||
KeyDownHandler, FocusHandler, BlurHandler, MouseDownHandler, | |||||
MouseUpHandler, TouchStartHandler { | |||||
/** | /** | ||||
* Current element hovered | * Current element hovered | ||||
*/ | */ | ||||
private boolean handledByFocus; | private boolean handledByFocus; | ||||
/** | |||||
* Indicates whether the tooltip is being called after a touch event. | |||||
*/ | |||||
private boolean touchInitiated = false; | |||||
/** | /** | ||||
* Locate the tooltip for given element | * Locate the tooltip for given element | ||||
* | * | ||||
@Override | @Override | ||||
public void onMouseMove(MouseMoveEvent mme) { | 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 | @Override | ||||
Profiler.enter("VTooltip.connectHandlersToWidget"); | Profiler.enter("VTooltip.connectHandlersToWidget"); | ||||
widget.addDomHandler(tooltipEventHandler, MouseMoveEvent.getType()); | widget.addDomHandler(tooltipEventHandler, MouseMoveEvent.getType()); | ||||
widget.addDomHandler(tooltipEventHandler, MouseDownEvent.getType()); | widget.addDomHandler(tooltipEventHandler, MouseDownEvent.getType()); | ||||
widget.addDomHandler(tooltipEventHandler, MouseUpEvent.getType()); | |||||
widget.addDomHandler(tooltipEventHandler, KeyDownEvent.getType()); | widget.addDomHandler(tooltipEventHandler, KeyDownEvent.getType()); | ||||
widget.addDomHandler(tooltipEventHandler, FocusEvent.getType()); | widget.addDomHandler(tooltipEventHandler, FocusEvent.getType()); | ||||
widget.addDomHandler(tooltipEventHandler, BlurEvent.getType()); | widget.addDomHandler(tooltipEventHandler, BlurEvent.getType()); | ||||
widget.addDomHandler(tooltipEventHandler, TouchStartEvent.getType()); | |||||
Profiler.leave("VTooltip.connectHandlersToWidget"); | Profiler.leave("VTooltip.connectHandlersToWidget"); | ||||
} | } | ||||
import com.google.gwt.core.client.GWT; | import com.google.gwt.core.client.GWT; | ||||
import com.google.gwt.dom.client.Document; | import com.google.gwt.dom.client.Document; | ||||
import com.google.gwt.dom.client.Element; | 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.SimplePanel; | ||||
import com.google.gwt.user.client.ui.Widget; | import com.google.gwt.user.client.ui.Widget; | ||||
import com.vaadin.client.BrowserInfo; | import com.vaadin.client.BrowserInfo; | ||||
public final class Slot extends SimplePanel { | public final class Slot extends SimplePanel { | ||||
private static final String ALIGN_CLASS_PREFIX = "v-align-"; | private static final String ALIGN_CLASS_PREFIX = "v-align-"; | ||||
private static final int TOUCH_ERROR_MESSAGE_HIDE_DELAY = 200; | |||||
private final VAbstractOrderedLayout layout; | private final VAbstractOrderedLayout layout; | ||||
private Element captionText; | private Element captionText; | ||||
private Icon icon; | private Icon icon; | ||||
private Element errorIcon; | private Element errorIcon; | ||||
private Element errorMessage; | |||||
private Element requiredIcon; | private Element requiredIcon; | ||||
private HandlerRegistration focusRegistration; | |||||
private HandlerRegistration blurRegistration; | |||||
private boolean labelClicked = false; | |||||
private ElementResizeListener captionResizeListener; | private ElementResizeListener captionResizeListener; | ||||
private ElementResizeListener widgetResizeListener; | private ElementResizeListener widgetResizeListener; | ||||
errorIcon.setClassName("v-errorindicator"); | errorIcon.setClassName("v-errorindicator"); | ||||
} | } | ||||
caption.appendChild(errorIcon); | 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) { | if (caption != null) { | ||||
} | } | ||||
} | } | ||||
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 | * Does the slot have a caption | ||||
*/ | */ |
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"; | |||||
} | |||||
} |