/* * Copyright 2000-2018 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.client; import com.google.gwt.aria.client.LiveValue; import com.google.gwt.aria.client.RelevantValue; import com.google.gwt.aria.client.Roles; import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.PreElement; 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.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; 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.user.client.Window; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.VOverlay; /** * A tooltip used by components. * * TODO open for extension */ public class VTooltip extends VOverlay { private static final String CLASSNAME = "v-tooltip"; private static final int MARGIN = 4; public static final int TOOLTIP_EVENTS = Event.ONKEYDOWN | Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONMOUSEMOVE | Event.ONCLICK; private static final int EVENT_XY_POSITION_OUTSIDE = -5000; VErrorMessage em = new VErrorMessage(); HTML description = GWT.create(HTML.class); private TooltipInfo currentTooltipInfo = new TooltipInfo(" "); private boolean closing = false; private boolean opening = false; // Open next tooltip faster. Disabled after 2 sec of showTooltip-silence. private boolean justClosed = false; private String uniqueId = DOM.createUniqueId(); private int maxWidth; // Delays for the tooltip, configurable on the server side private int openDelay; private int quickOpenDelay; private int quickOpenTimeout; private int closeTimeout; /** * Current element hovered */ private com.google.gwt.dom.client.Element currentElement = null; private int tooltipEventMouseX; private int tooltipEventMouseY; /** * Used to show tooltips; usually used via the singleton in * {@link ApplicationConnection}. NOTE that #setOwner(Widget)} should be * called after instantiating. * * @see ApplicationConnection#getVTooltip() */ public VTooltip() { super(false, false); // no autohide, not modal setStyleName(CLASSNAME); FlowPanel layout = new FlowPanel(); setWidget(layout); layout.add(em); description.setStyleName(CLASSNAME + "-text"); layout.add(description); // When a tooltip is shown, the content of the tooltip changes. With a // tooltip being a live-area, this change is notified to a assistive // device. Roles.getTooltipRole().set(getElement()); Roles.getTooltipRole().setAriaLiveProperty(getElement(), LiveValue.ASSERTIVE); Roles.getTooltipRole().setAriaRelevantProperty(getElement(), RelevantValue.ADDITIONS); // Tooltip needs to be on top of other VOverlay elements. setZIndex(VOverlay.Z_INDEX + 1); } /** * Show the tooltip with the provided info for assistive devices. * * @param info * with the content of the tooltip */ public void showAssistive(TooltipInfo info) { updatePosition(null, true); setTooltipText(info); showTooltip(); } /** * Initialize the tooltip overlay for assistive devices. * * @since 7.2.4 */ public void initializeAssistiveTooltips() { updatePosition(null, true); setTooltipText(new TooltipInfo(" ")); showTooltip(); hideTooltip(); description.getParent().getElement().getStyle().clearWidth(); } private void setTooltipText(TooltipInfo info) { if (info.getErrorMessage() != null && !info.getErrorMessage().isEmpty()) { em.setVisible(true); em.updateMessage(info.getErrorMessage()); em.updateErrorLevel(info.getErrorLevel()); } else { em.setVisible(false); } if (info.getTitle() != null && !info.getTitle().isEmpty()) { switch (info.getContentMode()) { case HTML: description.setHTML(info.getTitle()); break; case TEXT: description.setText(info.getTitle()); break; case PREFORMATTED: PreElement preElement = Document.get().createPreElement(); preElement.addClassName(CLASSNAME + "-pre"); preElement.setInnerText(info.getTitle()); // clear existing content description.setHTML(""); // add preformatted text to dom description.getElement().appendChild(preElement); break; default: break; } /* * Issue #11871: to correctly update the offsetWidth of description * element we need to clear style width of its parent DIV from old * value (in some strange cases this width=[tooltip MAX_WIDTH] after * tooltip text has been already updated to new shortly value: * *