diff options
author | Adam Wagner <wbadam@users.noreply.github.com> | 2017-09-27 10:02:29 +0300 |
---|---|---|
committer | Henri Sara <henri.sara@gmail.com> | 2017-09-27 10:02:29 +0300 |
commit | 697f770287bb786b6b5d4944a9202d145e4251f5 (patch) | |
tree | 2533cf5d0392129f8094f5d02df15c883f00f304 | |
parent | 9776ea2e85468256c70b8618c0e1a2a7ccb8199b (diff) | |
download | vaadin-framework-697f770287bb786b6b5d4944a9202d145e4251f5.tar.gz vaadin-framework-697f770287bb786b6b5d4944a9202d145e4251f5.zip |
Implement error level on client side (#9817)
Add additional class names and style to components and error indicators to distinguish different error levels.
Vaadin 8 implementation of #9816. Cherry picked changes and added compatibility package component changes and tests.
Resolves #3139
55 files changed, 1408 insertions, 255 deletions
diff --git a/all/src/main/templates/release-notes.html b/all/src/main/templates/release-notes.html index fab73eff2a..7087b6c46c 100644 --- a/all/src/main/templates/release-notes.html +++ b/all/src/main/templates/release-notes.html @@ -106,6 +106,8 @@ <li><tt>DataCommunicator</tt> method <tt>getDataProviderSize</tt> is now <tt>public</tt>, not <tt>protected</tt>.</li> <li><tt>Binder</tt> method <tt>getBindings</tt> now returns a Collection, not a Set.</li> <li><tt>BindingBuilder</tt> now works like a proper builder. Adding a converter will not mark Binding as <tt>bound</tt> allowing chaining to the same object.</li> + <li><tt>ErrorLevel</tt> is removed from <tt>ErrorMessage</tt> and now <tt>com.vaadin.shared.ui.ErrorLevel</tt> should be used.</li> + <li>Error indicators are now <tt><span class="v-errorindicator"></span></tt> elements.</li> <h2>For incompatible or behaviour-altering changes in 8.1, please see <a href="https://vaadin.com/download/release/8.1/8.1.0/release-notes.html#incompatible">8.1 release notes</a></h2> diff --git a/client/src/main/java/com/vaadin/client/StyleConstants.java b/client/src/main/java/com/vaadin/client/StyleConstants.java index 3b587ce233..13549b4938 100644 --- a/client/src/main/java/com/vaadin/client/StyleConstants.java +++ b/client/src/main/java/com/vaadin/client/StyleConstants.java @@ -44,4 +44,9 @@ public class StyleConstants { public static final String REQUIRED_EXT = "-required"; public static final String ERROR_EXT = "-error"; + + /** + * Style name and style name prefix for the error indicator element. + */ + public static final String STYLE_NAME_ERROR_INDICATOR = "v-errorindicator"; } diff --git a/client/src/main/java/com/vaadin/client/TooltipInfo.java b/client/src/main/java/com/vaadin/client/TooltipInfo.java index a84e45e988..1f01dab811 100644 --- a/client/src/main/java/com/vaadin/client/TooltipInfo.java +++ b/client/src/main/java/com/vaadin/client/TooltipInfo.java @@ -16,8 +16,13 @@ package com.vaadin.client; import com.vaadin.shared.ui.ContentMode; +import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.shared.util.SharedUtil; +/** + * An object that contains information about a tooltip, such as the tooltip's + * title, error message, error level and an ID. + */ public class TooltipInfo { private String title; @@ -26,14 +31,25 @@ public class TooltipInfo { private String errorMessageHtml; + private ErrorLevel errorLevel; + // Contains the tooltip's identifier. If a tooltip's contents and this // identifier haven't changed, the tooltip won't be updated in subsequent // events. private Object identifier; + /** + * Constructs a new tooltip info instance. + */ public TooltipInfo() { } + /** + * Constructs a new tooltip info instance. + * + * @param tooltip + * tooltip title + */ public TooltipInfo(String tooltip) { this(tooltip, ContentMode.PREFORMATTED); } @@ -41,12 +57,12 @@ public class TooltipInfo { /** * Constructs a new instance using the {@code tooltip} for the title and * {@code errorMessage} as a description. - * + * * @param tooltip * tooltip title * @param errorMessage * error description - * + * * @deprecated use {@link #TooltipInfo(String, ContentMode, String)} instead */ @Deprecated @@ -57,13 +73,14 @@ public class TooltipInfo { /** * Constructs a new instance using the {@code tooltip} for the title, * {@code errorMessage} as a description and {@code identifier} as its id. - * + * * @param tooltip * tooltip title * @param errorMessage * error description * @param identifier - * + * the tooltip's identifier + * * @deprecated use {@link #TooltipInfo(String, ContentMode, String, Object)} * instead */ @@ -72,56 +89,195 @@ public class TooltipInfo { this(tooltip, ContentMode.HTML, errorMessage, identifier); } + /** + * Constructs a new instance using the {@code tooltip} for the title, + * {@code errorMessage} as a description, {@code identifier} as its id and + * {@code errorLevel} as the error level. + * + * @param tooltip + * tooltip title + * @param errorMessage + * error description + * @param identifier + * the tooltip's identifier + * @param errorLevel + * error level + * + * @deprecated use {@link #TooltipInfo(String, ContentMode, String, Object, + * ErrorLevel)} instead + * @since 8.2 + */ + @Deprecated + public TooltipInfo(String tooltip, String errorMessage, Object identifier, + ErrorLevel errorLevel) { + this(tooltip, ContentMode.HTML, errorMessage, identifier, errorLevel); + } + + /** + * Constructs a new tooltip info instance. + * + * @param tooltip + * tooltip title + * @param mode + * content mode + */ public TooltipInfo(String tooltip, ContentMode mode) { setTitle(tooltip); setContentMode(mode); } + /** + * Constructs a new tooltip info instance. + * + * @param tooltip + * tooltip title + * @param mode + * content mode + * @param errorMessage + * error message + */ public TooltipInfo(String tooltip, ContentMode mode, String errorMessage) { this(tooltip, mode, errorMessage, null); } + /** + * Constructs a new tooltip info instance. + * + * @param tooltip + * tooltip title + * @param mode + * content mode + * @param errorMessage + * error message + * @param identifier + * the tooltip's identifier + */ public TooltipInfo(String tooltip, ContentMode mode, String errorMessage, Object identifier) { + this(tooltip, mode, errorMessage, identifier, null); + } + + /** + * Constructs a new tooltip info instance. + * + * @param tooltip + * tooltip title + * @param mode + * content mode + * @param errorMessage + * error message + * @param identifier + * the tooltip's identifier + * @param errorLevel + * error level + */ + public TooltipInfo(String tooltip, ContentMode mode, String errorMessage, + Object identifier, ErrorLevel errorLevel) { setIdentifier(identifier); setTitle(tooltip); setContentMode(mode); setErrorMessage(errorMessage); + setErrorLevel(errorLevel); } + /** + * Sets the tooltip's identifier. + * + * @param identifier + * the identifier to set + */ public void setIdentifier(Object identifier) { this.identifier = identifier; } + /** + * Gets the tooltip's identifier. + * + * @return the identifier + */ public Object getIdentifier() { return identifier; } + /** + * Gets the tooltip title. + * + * @return the title + */ public String getTitle() { return title; } + /** + * Sets the tooltip title. + * + * @param title + * the title to set + */ public void setTitle(String title) { this.title = title; } + /** + * Gets the error message. + * + * @return the error message + */ public String getErrorMessage() { return errorMessageHtml; } + /** + * Sets the error message. + * + * @param errorMessage + * the error message to set + */ public void setErrorMessage(String errorMessage) { errorMessageHtml = errorMessage; } + /** + * Gets the tooltip title's content mode. + * + * @return the content mode + */ public ContentMode getContentMode() { return contentMode; } + /** + * Sets the tooltip title's content mode. + * + * @param contentMode + * the content mode to set + */ public void setContentMode(ContentMode contentMode) { this.contentMode = contentMode; } /** + * Gets the error level. + * + * @return the error level + * @since + */ + public ErrorLevel getErrorLevel() { + return errorLevel; + } + + /** + * Sets the error level. + * + * @param errorLevel + * the error level to set + * @since + */ + public void setErrorLevel(ErrorLevel errorLevel) { + this.errorLevel = errorLevel; + } + + /** * Checks is a message has been defined for the tooltip. * * @return true if title or error message is present, false if both are @@ -132,9 +288,19 @@ public class TooltipInfo { || (errorMessageHtml != null && !errorMessageHtml.isEmpty()); } + /** + * Indicates whether another tooltip info instance is equal to this one. Two + * instances are equal if their title, error message, error level and + * identifier are equal. + * + * @param other + * the reference tooltip info instance with which to compare + * @return {@code true} if the instances are equal, {@code false} otherwise + */ public boolean equals(TooltipInfo other) { return (other != null && SharedUtil.equals(other.title, title) && SharedUtil.equals(other.errorMessageHtml, errorMessageHtml) + && SharedUtil.equals(other.errorLevel, errorLevel) && other.identifier == identifier); } } diff --git a/client/src/main/java/com/vaadin/client/VCaption.java b/client/src/main/java/com/vaadin/client/VCaption.java index 1bff175d7e..f7d7d55ffe 100644 --- a/client/src/main/java/com/vaadin/client/VCaption.java +++ b/client/src/main/java/com/vaadin/client/VCaption.java @@ -25,8 +25,10 @@ import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasHTML; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.HasErrorIndicator; +import com.vaadin.client.ui.HasErrorIndicatorElement; import com.vaadin.client.ui.HasRequiredIndicator; import com.vaadin.client.ui.Icon; import com.vaadin.client.ui.ImageIcon; @@ -34,8 +36,9 @@ import com.vaadin.client.ui.aria.AriaHelper; import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.ComponentConstants; import com.vaadin.shared.ui.ComponentStateUtil; +import com.vaadin.shared.ui.ErrorLevel; -public class VCaption extends HTML { +public class VCaption extends HTML implements HasErrorIndicatorElement { public static final String CLASSNAME = "v-caption"; @@ -259,23 +262,17 @@ public class VCaption extends HTML { AriaHelper.handleInputInvalid(owner.getWidget(), showError); if (showError) { - if (errorIndicatorElement == null) { - errorIndicatorElement = DOM.createDiv(); - DOM.setInnerHTML(errorIndicatorElement, " "); - DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); + setErrorIndicatorElementVisible(true); - DOM.insertChild(getElement(), errorIndicatorElement, - getInsertPosition(InsertPosition.ERROR)); + // Hide error indicator from assistive devices + Roles.getTextboxRole() + .setAriaHiddenState(errorIndicatorElement, true); - // Hide error indicator from assistive devices - Roles.getTextboxRole().setAriaHiddenState(errorIndicatorElement, - true); - } - } else if (errorIndicatorElement != null) { - // Remove existing - getElement().removeChild(errorIndicatorElement); - errorIndicatorElement = null; + ErrorUtil.setErrorLevelStyle(errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, + owner.getState().errorLevel); + } else { + setErrorIndicatorElementVisible(false); } return (wasPlacedAfterComponent != placedAfterComponent); @@ -322,6 +319,14 @@ public class VCaption extends HTML { public boolean updateCaptionWithoutOwner(String caption, boolean disabled, boolean hasDescription, boolean hasError, String iconURL, String iconAltText) { + return updateCaptionWithoutOwner(caption, disabled, hasDescription, + hasError, null, iconURL, iconAltText); + } + + @Deprecated + public boolean updateCaptionWithoutOwner(String caption, boolean disabled, + boolean hasDescription, boolean hasError, ErrorLevel errorLevel, + String iconURL, String iconAltText) { boolean wasPlacedAfterComponent = placedAfterComponent; // Caption is placed after component unless there is some part which @@ -401,19 +406,11 @@ public class VCaption extends HTML { } if (hasError) { - if (errorIndicatorElement == null) { - errorIndicatorElement = DOM.createDiv(); - DOM.setInnerHTML(errorIndicatorElement, " "); - DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); - - DOM.insertChild(getElement(), errorIndicatorElement, - getInsertPosition(InsertPosition.ERROR)); - } - } else if (errorIndicatorElement != null) { - // Remove existing - getElement().removeChild(errorIndicatorElement); - errorIndicatorElement = null; + setErrorIndicatorElementVisible(true); + ErrorUtil.setErrorLevelStyle(errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel); + } else { + setErrorIndicatorElementVisible(false); } return (wasPlacedAfterComponent != placedAfterComponent); @@ -775,4 +772,23 @@ public class VCaption extends HTML { private static Logger getLogger() { return Logger.getLogger(VCaption.class.getName()); } + + @Override + public Element getErrorIndicatorElement() { + return errorIndicatorElement; + } + + @Override + public void setErrorIndicatorElementVisible(boolean visible) { + if (visible) { + if (errorIndicatorElement == null) { + errorIndicatorElement = ErrorUtil.createErrorIndicatorElement(); + DOM.insertChild(getElement(), errorIndicatorElement, + getInsertPosition(InsertPosition.ERROR)); + } + } else if (errorIndicatorElement != null) { + getElement().removeChild(errorIndicatorElement); + errorIndicatorElement = null; + } + } } diff --git a/client/src/main/java/com/vaadin/client/VErrorMessage.java b/client/src/main/java/com/vaadin/client/VErrorMessage.java index 0baa1baff1..7caffa1275 100644 --- a/client/src/main/java/com/vaadin/client/VErrorMessage.java +++ b/client/src/main/java/com/vaadin/client/VErrorMessage.java @@ -22,6 +22,8 @@ import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ui.VOverlay; +import com.vaadin.client.WidgetUtil.ErrorUtil; +import com.vaadin.shared.ui.ErrorLevel; public class VErrorMessage extends FlowPanel { public static final String CLASSNAME = "v-errormessage"; @@ -58,6 +60,18 @@ public class VErrorMessage extends FlowPanel { } /** + * Sets the correct error level style name for the error message and removes + * all previous style names. + * + * @param errorLevel + * error level + * @since + */ + public void updateErrorLevel(ErrorLevel errorLevel) { + ErrorUtil.setErrorLevelStyle(getStyleElement(), CLASSNAME, errorLevel); + } + + /** * Shows this error message next to given element. * * @param indicatorElement diff --git a/client/src/main/java/com/vaadin/client/VTooltip.java b/client/src/main/java/com/vaadin/client/VTooltip.java index 74da680c66..84647abf9a 100644 --- a/client/src/main/java/com/vaadin/client/VTooltip.java +++ b/client/src/main/java/com/vaadin/client/VTooltip.java @@ -138,6 +138,7 @@ public class VTooltip extends VOverlay { && !info.getErrorMessage().isEmpty()) { em.setVisible(true); em.updateMessage(info.getErrorMessage()); + em.updateErrorLevel(info.getErrorLevel()); } else { em.setVisible(false); } @@ -459,6 +460,7 @@ public class VTooltip extends VOverlay { @Override public void hide() { em.updateMessage(""); + em.updateErrorLevel(null); description.setHTML(""); updatePosition(null, true); diff --git a/client/src/main/java/com/vaadin/client/WidgetUtil.java b/client/src/main/java/com/vaadin/client/WidgetUtil.java index 0aced86b03..fed9320edc 100644 --- a/client/src/main/java/com/vaadin/client/WidgetUtil.java +++ b/client/src/main/java/com/vaadin/client/WidgetUtil.java @@ -44,6 +44,7 @@ import com.google.gwt.user.client.EventListener; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; +import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.shared.util.SharedUtil; /** @@ -790,7 +791,7 @@ public class WidgetUtil { com.google.gwt.dom.client.Element el, String p) /*-{ try { - + if (el.currentStyle) { // IE return el.currentStyle[p]; @@ -805,7 +806,7 @@ public class WidgetUtil { } catch (e) { return ""; } - + }-*/; /** @@ -819,7 +820,7 @@ public class WidgetUtil { try { el.focus(); } catch (e) { - + } }-*/; @@ -1172,7 +1173,7 @@ public class WidgetUtil { if ($wnd.document.activeElement) { return $wnd.document.activeElement; } - + return null; }-*/; @@ -1243,11 +1244,11 @@ public class WidgetUtil { /*-{ var top = elem.offsetTop; var height = elem.offsetHeight; - + if (elem.parentNode != elem.offsetParent) { top -= elem.parentNode.offsetTop; } - + var cur = elem.parentNode; while (cur && (cur.nodeType == 1)) { if (top < cur.scrollTop) { @@ -1256,12 +1257,12 @@ public class WidgetUtil { if (top + height > cur.scrollTop + cur.clientHeight) { cur.scrollTop = (top + height) - cur.clientHeight; } - + var offsetTop = cur.offsetTop; if (cur.parentNode != cur.offsetParent) { offsetTop -= cur.parentNode.offsetTop; } - + top += offsetTop - cur.scrollTop; cur = cur.parentNode; } @@ -1710,7 +1711,7 @@ public class WidgetUtil { } var heightWithoutBorder = cloneElement.offsetHeight; parentElement.removeChild(cloneElement); - + return heightWithBorder - heightWithoutBorder; } }-*/; @@ -1866,4 +1867,48 @@ public class WidgetUtil { int relativeTop = element.getAbsoluteTop() - Window.getScrollTop(); return WidgetUtil.getTouchOrMouseClientY(event) - relativeTop; } + + /** + * Utility methods for displaying error message on components. + * + * @since 8.2 + */ + public static class ErrorUtil { + + /** + * Sets the error level style name for the given element and removes all + * previously applied error level style names. The style name has the + * {@code prefix-errorLevel} format. + * + * @param element + * element to apply the style name to + * @param prefix + * part of the style name before the error level string + * @param errorLevel + * error level for which the style will be applied + */ + public static void setErrorLevelStyle(Element element, String prefix, + ErrorLevel errorLevel) { + for (ErrorLevel errorLevelValue : ErrorLevel.values()) { + String className = + prefix + "-" + errorLevelValue.toString().toLowerCase(); + if (errorLevel == errorLevelValue) { + element.addClassName(className); + } else { + element.removeClassName(className); + } + } + } + + /** + * Creates an element to use by widgets as an error indicator. + * + * @return the error indicator element + */ + public static Element createErrorIndicatorElement() { + Element indicator = DOM.createSpan(); + indicator.setClassName(StyleConstants.STYLE_NAME_ERROR_INDICATOR); + return indicator; + } + } } diff --git a/client/src/main/java/com/vaadin/client/ui/AbstractComponentConnector.java b/client/src/main/java/com/vaadin/client/ui/AbstractComponentConnector.java index 7ce3e5c9b7..d3b595b55a 100644 --- a/client/src/main/java/com/vaadin/client/ui/AbstractComponentConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/AbstractComponentConnector.java @@ -46,6 +46,7 @@ import com.vaadin.client.UIDL; import com.vaadin.client.Util; import com.vaadin.client.VConsole; import com.vaadin.client.WidgetUtil; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.extensions.DragSourceExtensionConnector; @@ -489,6 +490,27 @@ public abstract class AbstractComponentConnector extends AbstractConnector Profiler.leave("AbstractComponentConnector.onStateChanged"); } + @OnStateChange({"errorMessage", "errorLevel"}) + private void setErrorLevel() { + // Add or remove the widget's error level style name + ErrorUtil.setErrorLevelStyle(getWidget().getElement(), + getWidget().getStylePrimaryName() + StyleConstants.ERROR_EXT, + getState().errorLevel); + + // Add or remove error indicator element + if (getWidget() instanceof HasErrorIndicatorElement) { + HasErrorIndicatorElement widget = (HasErrorIndicatorElement) getWidget(); + if (getState().errorMessage != null) { + widget.setErrorIndicatorElementVisible(true); + ErrorUtil.setErrorLevelStyle(widget.getErrorIndicatorElement(), + StyleConstants.STYLE_NAME_ERROR_INDICATOR, + getState().errorLevel); + } else { + widget.setErrorIndicatorElementVisible(false); + } + } + } + @Override public void setWidgetEnabled(boolean widgetEnabled) { // add or remove v-disabled style name from the widget @@ -764,7 +786,8 @@ public abstract class AbstractComponentConnector extends AbstractConnector @Override public TooltipInfo getTooltipInfo(Element element) { return new TooltipInfo(getState().description, - getState().descriptionContentMode, getState().errorMessage); + getState().descriptionContentMode, getState().errorMessage, + null, getState().errorLevel); } @Override diff --git a/client/src/main/java/com/vaadin/client/ui/HasErrorIndicatorElement.java b/client/src/main/java/com/vaadin/client/ui/HasErrorIndicatorElement.java new file mode 100644 index 0000000000..8ee0e5e757 --- /dev/null +++ b/client/src/main/java/com/vaadin/client/ui/HasErrorIndicatorElement.java @@ -0,0 +1,42 @@ +/* + * Copyright 2000-2016 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.ui; + +import com.google.gwt.dom.client.Element; + +/** + * Implemented by widgets supporting an error indicator. + * + * @since 8.2 + */ +public interface HasErrorIndicatorElement { + + /** + * Gets the error indicator element. + * + * @return the error indicator element + */ + Element getErrorIndicatorElement(); + + /** + * Sets the visibility of the error indicator element. + * + * @param visible + * {@code true} to show the error indicator element, {@code false} + * to hide it + */ + void setErrorIndicatorElementVisible(boolean visible); +} diff --git a/client/src/main/java/com/vaadin/client/ui/VAccordion.java b/client/src/main/java/com/vaadin/client/ui/VAccordion.java index 16c16935d0..642c647a62 100644 --- a/client/src/main/java/com/vaadin/client/ui/VAccordion.java +++ b/client/src/main/java/com/vaadin/client/ui/VAccordion.java @@ -364,8 +364,10 @@ public class VAccordion extends VTabsheetBase { caption.updateCaptionWithoutOwner(tabState.caption, !tabState.enabled, hasAttribute(tabState.description), hasAttribute(tabState.componentError), + tabState.componentErrorLevel, connector.getResourceUrl( - ComponentConstants.ICON_RESOURCE + tabState.key)); + ComponentConstants.ICON_RESOURCE + tabState.key), + tabState.iconAltText); } private boolean hasAttribute(String string) { diff --git a/client/src/main/java/com/vaadin/client/ui/VButton.java b/client/src/main/java/com/vaadin/client/ui/VButton.java index 0e738032b5..725931008e 100644 --- a/client/src/main/java/com/vaadin/client/ui/VButton.java +++ b/client/src/main/java/com/vaadin/client/ui/VButton.java @@ -30,8 +30,10 @@ import com.vaadin.client.ApplicationConnection; import com.vaadin.client.BrowserInfo; import com.vaadin.client.Util; import com.vaadin.client.WidgetUtil; +import com.vaadin.client.WidgetUtil.ErrorUtil; -public class VButton extends FocusWidget implements ClickHandler { +public class VButton extends FocusWidget implements ClickHandler, + HasErrorIndicatorElement { public static final String CLASSNAME = "v-button"; private static final String CLASSNAME_PRESSED = "v-pressed"; @@ -48,7 +50,7 @@ public class VButton extends FocusWidget implements ClickHandler { public final Element wrapper = DOM.createSpan(); /** For internal use only. May be removed or replaced in the future. */ - public Element errorIndicatorElement; + private Element errorIndicatorElement; /** For internal use only. May be removed or replaced in the future. */ public final Element captionElement = DOM.createSpan(); @@ -481,4 +483,21 @@ public class VButton extends FocusWidget implements ClickHandler { return ret; }-*/; + @Override + public Element getErrorIndicatorElement() { + return errorIndicatorElement; + } + + @Override + public void setErrorIndicatorElementVisible(boolean visible) { + if (visible) { + if (errorIndicatorElement == null) { + errorIndicatorElement = ErrorUtil.createErrorIndicatorElement(); + wrapper.insertFirst(errorIndicatorElement); + } + } else if (errorIndicatorElement != null) { + wrapper.removeChild(errorIndicatorElement); + errorIndicatorElement = null; + } + } } diff --git a/client/src/main/java/com/vaadin/client/ui/VCheckBox.java b/client/src/main/java/com/vaadin/client/ui/VCheckBox.java index b2f78dce31..18140c203d 100644 --- a/client/src/main/java/com/vaadin/client/ui/VCheckBox.java +++ b/client/src/main/java/com/vaadin/client/ui/VCheckBox.java @@ -25,12 +25,14 @@ import com.vaadin.client.ApplicationConnection; import com.vaadin.client.BrowserInfo; import com.vaadin.client.Util; import com.vaadin.client.VTooltip; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.ui.aria.AriaHelper; import com.vaadin.client.ui.aria.HandlesAriaInvalid; import com.vaadin.client.ui.aria.HandlesAriaRequired; public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox - implements Field, HandlesAriaInvalid, HandlesAriaRequired { + implements Field, HandlesAriaInvalid, HandlesAriaRequired, + HasErrorIndicatorElement { public static final String CLASSNAME = "v-checkbox"; @@ -41,7 +43,7 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox public ApplicationConnection client; /** For internal use only. May be removed or replaced in the future. */ - public Element errorIndicatorElement; + private Element errorIndicatorElement; /** For internal use only. May be removed or replaced in the future. */ public Icon icon; @@ -101,4 +103,24 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox public void setAriaInvalid(boolean invalid) { AriaHelper.handleInputInvalid(getCheckBoxElement(), invalid); } + + @Override + public Element getErrorIndicatorElement() { + return errorIndicatorElement; + } + + @Override + public void setErrorIndicatorElementVisible(boolean visible) { + if (visible) { + if (errorIndicatorElement == null) { + errorIndicatorElement = ErrorUtil.createErrorIndicatorElement(); + getElement().appendChild(errorIndicatorElement); + DOM.sinkEvents(errorIndicatorElement, + VTooltip.TOOLTIP_EVENTS | Event.ONCLICK); + } + } else if (errorIndicatorElement != null) { + getElement().removeChild(errorIndicatorElement); + errorIndicatorElement = null; + } + } } diff --git a/client/src/main/java/com/vaadin/client/ui/VFormLayout.java b/client/src/main/java/com/vaadin/client/ui/VFormLayout.java index a8a43a2d8d..5704dc497d 100644 --- a/client/src/main/java/com/vaadin/client/ui/VFormLayout.java +++ b/client/src/main/java/com/vaadin/client/ui/VFormLayout.java @@ -34,10 +34,12 @@ import com.vaadin.client.ComponentConnector; import com.vaadin.client.Focusable; import com.vaadin.client.StyleConstants; import com.vaadin.client.VTooltip; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.ui.aria.AriaHelper; import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.ComponentConstants; import com.vaadin.shared.ui.ComponentStateUtil; +import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.shared.ui.MarginInfo; /** @@ -201,10 +203,10 @@ public class VFormLayout extends SimplePanel { } public void updateError(Widget widget, String errorMessage, - boolean hideErrors) { + ErrorLevel errorLevel, boolean hideErrors) { final ErrorFlag e = widgetToError.get(widget); if (e != null) { - e.updateError(errorMessage, hideErrors); + e.updateError(errorMessage, errorLevel, hideErrors); } } @@ -340,7 +342,7 @@ public class VFormLayout extends SimplePanel { } /** For internal use only. May be removed or replaced in the future. */ - public class ErrorFlag extends HTML { + public class ErrorFlag extends HTML implements HasErrorIndicatorElement { private static final String CLASSNAME = VFormLayout.CLASSNAME + "-error-indicator"; Element errorIndicatorElement; @@ -361,7 +363,8 @@ public class VFormLayout extends SimplePanel { return owner; } - public void updateError(String errorMessage, boolean hideErrors) { + public void updateError(String errorMessage, ErrorLevel errorLevel, + boolean hideErrors) { boolean showError = null != errorMessage; if (hideErrors) { showError = false; @@ -370,24 +373,37 @@ public class VFormLayout extends SimplePanel { AriaHelper.handleInputInvalid(owner.getWidget(), showError); if (showError) { - if (errorIndicatorElement == null) { - errorIndicatorElement = DOM.createDiv(); - DOM.setInnerHTML(errorIndicatorElement, " "); - DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); - DOM.appendChild(getElement(), errorIndicatorElement); + setErrorIndicatorElementVisible(true); - // Hide the error indicator from screen reader, as this - // information is set directly at the input field - Roles.getFormRole() - .setAriaHiddenState(errorIndicatorElement, true); - } + // Hide the error indicator from screen reader, as this + // information is set directly at the input field + Roles.getFormRole() + .setAriaHiddenState(errorIndicatorElement, true); + + ErrorUtil.setErrorLevelStyle(errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel); + } else { + setErrorIndicatorElementVisible(false); + } + } + + @Override + public Element getErrorIndicatorElement() { + return errorIndicatorElement; + } + @Override + public void setErrorIndicatorElementVisible(boolean visible) { + if (visible) { + if (errorIndicatorElement == null) { + errorIndicatorElement = ErrorUtil + .createErrorIndicatorElement(); + getElement().appendChild(errorIndicatorElement); + } } else if (errorIndicatorElement != null) { - DOM.removeChild(getElement(), errorIndicatorElement); + getElement().removeChild(errorIndicatorElement); errorIndicatorElement = null; } } - } } diff --git a/client/src/main/java/com/vaadin/client/ui/VLink.java b/client/src/main/java/com/vaadin/client/ui/VLink.java index 84aac0f17e..28e262b110 100644 --- a/client/src/main/java/com/vaadin/client/ui/VLink.java +++ b/client/src/main/java/com/vaadin/client/ui/VLink.java @@ -25,9 +25,11 @@ import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasEnabled; import com.vaadin.client.Util; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.shared.ui.BorderStyle; -public class VLink extends HTML implements ClickHandler, HasEnabled { +public class VLink extends HTML implements ClickHandler, HasEnabled, + HasErrorIndicatorElement { public static final String CLASSNAME = "v-link"; @@ -59,7 +61,7 @@ public class VLink extends HTML implements ClickHandler, HasEnabled { public int targetHeight; /** For internal use only. May be removed or replaced in the future. */ - public Element errorIndicatorElement; + private Element errorIndicatorElement; /** For internal use only. May be removed or replaced in the future. */ public final Element anchor = DOM.createAnchor(); @@ -145,4 +147,21 @@ public class VLink extends HTML implements ClickHandler, HasEnabled { this.enabled = enabled; } + @Override + public Element getErrorIndicatorElement() { + return errorIndicatorElement; + } + + @Override + public void setErrorIndicatorElementVisible(boolean visible) { + if (visible) { + if (errorIndicatorElement == null) { + errorIndicatorElement = ErrorUtil.createErrorIndicatorElement(); + getElement().insertFirst(errorIndicatorElement); + } + } else if (errorIndicatorElement != null) { + getElement().removeChild(errorIndicatorElement); + errorIndicatorElement = null; + } + } } diff --git a/client/src/main/java/com/vaadin/client/ui/VNativeButton.java b/client/src/main/java/com/vaadin/client/ui/VNativeButton.java index ec95a28755..db8e820b82 100644 --- a/client/src/main/java/com/vaadin/client/ui/VNativeButton.java +++ b/client/src/main/java/com/vaadin/client/ui/VNativeButton.java @@ -27,10 +27,12 @@ import com.vaadin.client.BrowserInfo; import com.vaadin.client.MouseEventDetailsBuilder; import com.vaadin.client.StyleConstants; import com.vaadin.client.Util; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.ui.button.ButtonServerRpc; -public class VNativeButton extends Button implements ClickHandler { +public class VNativeButton extends Button implements ClickHandler, + HasErrorIndicatorElement { public static final String CLASSNAME = "v-nativebutton"; @@ -44,7 +46,7 @@ public class VNativeButton extends Button implements ClickHandler { public ButtonServerRpc buttonRpcProxy; /** For internal use only. May be removed or replaced in the future. */ - public Element errorIndicatorElement; + private Element errorIndicatorElement; /** For internal use only. May be removed or replaced in the future. */ public final Element captionElement = DOM.createSpan(); @@ -159,4 +161,22 @@ public class VNativeButton extends Button implements ClickHandler { clickPending = false; } + @Override + public Element getErrorIndicatorElement() { + return errorIndicatorElement; + } + + @Override + public void setErrorIndicatorElementVisible(boolean visible) { + if (visible) { + if (errorIndicatorElement == null) { + errorIndicatorElement = ErrorUtil.createErrorIndicatorElement(); + getElement() + .insertBefore(errorIndicatorElement, captionElement); + } + } else if (errorIndicatorElement != null) { + getElement().removeChild(errorIndicatorElement); + errorIndicatorElement = null; + } + } } diff --git a/client/src/main/java/com/vaadin/client/ui/VPanel.java b/client/src/main/java/com/vaadin/client/ui/VPanel.java index fa4a939a95..bf41ef1f9e 100644 --- a/client/src/main/java/com/vaadin/client/ui/VPanel.java +++ b/client/src/main/java/com/vaadin/client/ui/VPanel.java @@ -24,11 +24,12 @@ import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.SimplePanel; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.Focusable; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler; -public class VPanel extends SimplePanel - implements ShortcutActionHandlerOwner, Focusable { +public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner, + Focusable, HasErrorIndicatorElement { public static final String CLASSNAME = "v-panel"; @@ -134,23 +135,6 @@ public class VPanel extends SimplePanel } /** For internal use only. May be removed or replaced in the future. */ - public void setErrorIndicatorVisible(boolean showError) { - if (showError) { - if (errorIndicatorElement == null) { - errorIndicatorElement = DOM.createSpan(); - DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); - DOM.sinkEvents(errorIndicatorElement, Event.MOUSEEVENTS); - sinkEvents(Event.MOUSEEVENTS); - } - DOM.insertBefore(captionNode, errorIndicatorElement, captionText); - } else if (errorIndicatorElement != null) { - DOM.removeChild(captionNode, errorIndicatorElement); - errorIndicatorElement = null; - } - } - - /** For internal use only. May be removed or replaced in the future. */ public void setIconUri(String iconUri, ApplicationConnection client) { if (icon != null) { captionNode.removeChild(icon.getElement()); @@ -201,4 +185,24 @@ public class VPanel extends SimplePanel } touchScrollHandler.addElement(contentNode); } + + @Override + public Element getErrorIndicatorElement() { + return errorIndicatorElement; + } + + @Override + public void setErrorIndicatorElementVisible(boolean visible) { + if (visible) { + if (errorIndicatorElement == null) { + errorIndicatorElement = ErrorUtil.createErrorIndicatorElement(); + DOM.sinkEvents(errorIndicatorElement, Event.MOUSEEVENTS); + sinkEvents(Event.MOUSEEVENTS); + captionNode.insertBefore(errorIndicatorElement, captionText); + } + } else if (errorIndicatorElement != null){ + captionNode.removeChild(errorIndicatorElement); + errorIndicatorElement = null; + } + } } diff --git a/client/src/main/java/com/vaadin/client/ui/VTabsheet.java b/client/src/main/java/com/vaadin/client/ui/VTabsheet.java index 52b48899dd..44814f9e0a 100644 --- a/client/src/main/java/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/main/java/com/vaadin/client/ui/VTabsheet.java @@ -340,7 +340,8 @@ public class VTabsheet extends VTabsheetBase || tabState.componentError != null) { setTooltipInfo(new TooltipInfo(tabState.description, tabState.descriptionContentMode, - tabState.componentError, this)); + tabState.componentError, this, + tabState.componentErrorLevel)); } else { setTooltipInfo(null); } @@ -352,6 +353,7 @@ public class VTabsheet extends VTabsheetBase boolean ret = updateCaptionWithoutOwner(captionString, !tabState.enabled, hasAttribute(tabState.description), hasAttribute(tabState.componentError), + tabState.componentErrorLevel, tab.getTabsheet().connector.getResourceUrl( ComponentConstants.ICON_RESOURCE + tabState.key), tabState.iconAltText); diff --git a/client/src/main/java/com/vaadin/client/ui/button/ButtonConnector.java b/client/src/main/java/com/vaadin/client/ui/button/ButtonConnector.java index b0d17465bb..eac2ffd11e 100644 --- a/client/src/main/java/com/vaadin/client/ui/button/ButtonConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/button/ButtonConnector.java @@ -20,7 +20,9 @@ import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.DOM; import com.vaadin.client.MouseEventDetailsBuilder; +import com.vaadin.client.StyleConstants; import com.vaadin.client.VCaption; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; @@ -50,22 +52,6 @@ public class ButtonConnector extends AbstractComponentConnector ConnectorFocusAndBlurHandler.addHandlers(this); } - @OnStateChange("errorMessage") - void setErrorMessage() { - if (null != getState().errorMessage) { - if (getWidget().errorIndicatorElement == null) { - getWidget().errorIndicatorElement = DOM.createSpan(); - getWidget().errorIndicatorElement - .setClassName("v-errorindicator"); - } - getWidget().wrapper.insertFirst(getWidget().errorIndicatorElement); - - } else if (getWidget().errorIndicatorElement != null) { - getWidget().wrapper.removeChild(getWidget().errorIndicatorElement); - getWidget().errorIndicatorElement = null; - } - } - @OnStateChange("resources") void onResourceChange() { if (getWidget().icon != null) { diff --git a/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java b/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java index cf39e5ee21..c02607790f 100644 --- a/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java @@ -21,8 +21,10 @@ import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.vaadin.client.MouseEventDetailsBuilder; +import com.vaadin.client.StyleConstants; import com.vaadin.client.VCaption; import com.vaadin.client.VTooltip; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractFieldConnector; @@ -66,27 +68,7 @@ public class CheckBoxConnector extends AbstractFieldConnector public void onStateChanged(StateChangeEvent stateChangeEvent) { super.onStateChanged(stateChangeEvent); - if (null != getState().errorMessage) { - getWidget().setAriaInvalid(true); - - if (getWidget().errorIndicatorElement == null) { - getWidget().errorIndicatorElement = DOM.createSpan(); - getWidget().errorIndicatorElement.setInnerHTML(" "); - DOM.setElementProperty(getWidget().errorIndicatorElement, - "className", "v-errorindicator"); - DOM.appendChild(getWidget().getElement(), - getWidget().errorIndicatorElement); - DOM.sinkEvents(getWidget().errorIndicatorElement, - VTooltip.TOOLTIP_EVENTS | Event.ONCLICK); - } else { - getWidget().errorIndicatorElement.getStyle().clearDisplay(); - } - } else if (getWidget().errorIndicatorElement != null) { - getWidget().errorIndicatorElement.getStyle() - .setDisplay(Display.NONE); - - getWidget().setAriaInvalid(false); - } + getWidget().setAriaInvalid(getState().errorMessage != null); getWidget().setAriaRequired(isRequiredIndicatorVisible()); if (isReadOnly()) { diff --git a/client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java b/client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java index ba1d79c776..ea9fd57c26 100644 --- a/client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java @@ -254,7 +254,8 @@ public class FormLayoutConnector extends AbstractLayoutConnector } getWidget().table.updateError(component.getWidget(), - component.getState().errorMessage, hideErrors); + component.getState().errorMessage, + component.getState().errorLevel, hideErrors); } @Override diff --git a/client/src/main/java/com/vaadin/client/ui/link/LinkConnector.java b/client/src/main/java/com/vaadin/client/ui/link/LinkConnector.java index e110bbb935..edc5449127 100644 --- a/client/src/main/java/com/vaadin/client/ui/link/LinkConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/link/LinkConnector.java @@ -18,7 +18,9 @@ package com.vaadin.client.ui.link; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.user.client.DOM; +import com.vaadin.client.StyleConstants; import com.vaadin.client.VCaption; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.Icon; @@ -70,20 +72,6 @@ public class LinkConnector extends AbstractComponentConnector { // Set link caption VCaption.setCaptionText(getWidget().captionElement, getState()); - // handle error - if (null != getState().errorMessage) { - if (getWidget().errorIndicatorElement == null) { - getWidget().errorIndicatorElement = DOM.createDiv(); - DOM.setElementProperty(getWidget().errorIndicatorElement, - "className", "v-errorindicator"); - } - DOM.insertChild(getWidget().getElement(), - getWidget().errorIndicatorElement, 0); - } else if (getWidget().errorIndicatorElement != null) { - getWidget().errorIndicatorElement.getStyle() - .setDisplay(Display.NONE); - } - if (getWidget().icon != null) { getWidget().anchor.removeChild(getWidget().icon.getElement()); getWidget().icon = null; diff --git a/client/src/main/java/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java b/client/src/main/java/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java index 18db2cf424..5560e9825c 100644 --- a/client/src/main/java/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java @@ -16,7 +16,9 @@ package com.vaadin.client.ui.nativebutton; import com.google.gwt.user.client.DOM; +import com.vaadin.client.StyleConstants; import com.vaadin.client.VCaption; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; @@ -55,23 +57,6 @@ public class NativeButtonConnector extends AbstractComponentConnector { // Set text VCaption.setCaptionText(getWidget(), getState()); - // handle error - if (null != getState().errorMessage) { - if (getWidget().errorIndicatorElement == null) { - getWidget().errorIndicatorElement = DOM.createSpan(); - getWidget().errorIndicatorElement - .setClassName("v-errorindicator"); - } - getWidget().getElement().insertBefore( - getWidget().errorIndicatorElement, - getWidget().captionElement); - - } else if (getWidget().errorIndicatorElement != null) { - getWidget().getElement() - .removeChild(getWidget().errorIndicatorElement); - getWidget().errorIndicatorElement = null; - } - if (getWidget().icon != null) { getWidget().getElement().removeChild(getWidget().icon.getElement()); getWidget().icon = null; diff --git a/client/src/main/java/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/main/java/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java index 5ab5f5fcda..ee8438de22 100644 --- a/client/src/main/java/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java @@ -275,8 +275,9 @@ public abstract class AbstractOrderedLayoutConnector slot.setCaptionResizeListener(null); } - slot.setCaption(caption, icon, styles, error, showError, required, - enabled, child.getState().captionAsHtml); + slot.setCaption(caption, icon, styles, error, + child.getState().errorLevel, showError, required, enabled, + child.getState().captionAsHtml); AriaHelper.handleInputRequired(child.getWidget(), required); AriaHelper.handleInputInvalid(child.getWidget(), showError); diff --git a/client/src/main/java/com/vaadin/client/ui/orderedlayout/Slot.java b/client/src/main/java/com/vaadin/client/ui/orderedlayout/Slot.java index d8e0544aaf..fb89972d04 100644 --- a/client/src/main/java/com/vaadin/client/ui/orderedlayout/Slot.java +++ b/client/src/main/java/com/vaadin/client/ui/orderedlayout/Slot.java @@ -30,16 +30,19 @@ import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.LayoutManager; import com.vaadin.client.StyleConstants; import com.vaadin.client.WidgetUtil; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.ui.FontIcon; +import com.vaadin.client.ui.HasErrorIndicatorElement; import com.vaadin.client.ui.Icon; import com.vaadin.client.ui.ImageIcon; import com.vaadin.client.ui.layout.ElementResizeListener; import com.vaadin.shared.ui.AlignmentInfo; +import com.vaadin.shared.ui.ErrorLevel; /** * Represents a slot which contains the actual widget in the layout. */ -public class Slot extends SimplePanel { +public class Slot extends SimplePanel implements HasErrorIndicatorElement { private static final String ALIGN_CLASS_PREFIX = "v-align-"; @@ -493,6 +496,37 @@ public class Slot extends SimplePanel { public void setCaption(String captionText, Icon icon, List<String> styles, String error, boolean showError, boolean required, boolean enabled, boolean captionAsHtml) { + setCaption(captionText, icon, styles, error, null, showError, required, + enabled, captionAsHtml); + } + + /** + * Set the caption of the slot + * + * @param captionText + * The text of the caption + * @param icon + * The icon + * @param styles + * The style names + * @param error + * The error message + * @param errorLevel + * The error level + * @param showError + * Should the error message be shown + * @param required + * Is the (field) required + * @param enabled + * Is the component enabled + * @param captionAsHtml + * true if the caption should be rendered as HTML, false + * otherwise + * @since 8.2 + */ + public void setCaption(String captionText, Icon icon, List<String> styles, + String error, ErrorLevel errorLevel, boolean showError, + boolean required, boolean enabled, boolean captionAsHtml) { // TODO place for optimization: check if any of these have changed // since last time, and only run those changes @@ -583,14 +617,11 @@ public class Slot extends SimplePanel { // Error if (error != null && showError) { - if (errorIcon == null) { - errorIcon = DOM.createSpan(); - errorIcon.setClassName("v-errorindicator"); - } - caption.appendChild(errorIcon); - } else if (errorIcon != null) { - errorIcon.removeFromParent(); - errorIcon = null; + setErrorIndicatorElementVisible(true); + ErrorUtil.setErrorLevelStyle(getErrorIndicatorElement(), + StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel); + } else { + setErrorIndicatorElementVisible(false); } if (caption != null) { @@ -799,4 +830,22 @@ public class Slot extends SimplePanel { return hasRelativeWidth(); } } + + @Override + public Element getErrorIndicatorElement() { + return errorIcon; + } + + @Override + public void setErrorIndicatorElementVisible(boolean visible) { + if (visible) { + if (errorIcon == null) { + errorIcon = ErrorUtil.createErrorIndicatorElement(); + } + caption.appendChild(errorIcon); + } else if (errorIcon != null) { + errorIcon.removeFromParent(); + errorIcon = null; + } + } } diff --git a/client/src/main/java/com/vaadin/client/ui/panel/PanelConnector.java b/client/src/main/java/com/vaadin/client/ui/panel/PanelConnector.java index 84ed73e537..25434e2701 100644 --- a/client/src/main/java/com/vaadin/client/ui/panel/PanelConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/panel/PanelConnector.java @@ -143,8 +143,6 @@ public class PanelConnector extends AbstractSingleComponentContainerConnector getWidget().setIconUri(null, client); } - getWidget().setErrorIndicatorVisible(isErrorIndicatorVisible()); - // We may have actions attached to this panel if (uidl.getChildCount() > 0) { final int cnt = uidl.getChildCount(); diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/checkbox/CheckBoxConnector.java b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/checkbox/CheckBoxConnector.java index d2a761ba0a..714367b0ae 100644 --- a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/checkbox/CheckBoxConnector.java +++ b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/checkbox/CheckBoxConnector.java @@ -21,8 +21,10 @@ import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.vaadin.client.MouseEventDetailsBuilder; +import com.vaadin.client.StyleConstants; import com.vaadin.client.VCaption; import com.vaadin.client.VTooltip; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; @@ -67,7 +69,7 @@ public class CheckBoxConnector extends AbstractFieldConnector getWidget().errorIndicatorElement = DOM.createSpan(); getWidget().errorIndicatorElement.setInnerHTML(" "); DOM.setElementProperty(getWidget().errorIndicatorElement, - "className", "v-errorindicator"); + "className", StyleConstants.STYLE_NAME_ERROR_INDICATOR); DOM.appendChild(getWidget().getElement(), getWidget().errorIndicatorElement); DOM.sinkEvents(getWidget().errorIndicatorElement, @@ -75,6 +77,11 @@ public class CheckBoxConnector extends AbstractFieldConnector } else { getWidget().errorIndicatorElement.getStyle().clearDisplay(); } + + ErrorUtil.setErrorLevelStyle(getWidget().errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, + getState().errorLevel); + } else if (getWidget().errorIndicatorElement != null) { getWidget().errorIndicatorElement.getStyle() .setDisplay(Display.NONE); diff --git a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/form/FormConnector.java b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/form/FormConnector.java index e904cd6803..ab28118c66 100644 --- a/compatibility-client/src/main/java/com/vaadin/v7/client/ui/form/FormConnector.java +++ b/compatibility-client/src/main/java/com/vaadin/v7/client/ui/form/FormConnector.java @@ -126,6 +126,7 @@ public class FormConnector extends AbstractComponentContainerConnector if (null != getState().errorMessage) { getWidget().errorMessage.updateMessage(getState().errorMessage); + getWidget().errorMessage.updateErrorLevel(getState().errorLevel); getWidget().errorMessage.setVisible(true); } else { getWidget().errorMessage.setVisible(false); diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java b/compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java index 2bb4065921..8bb2cefccc 100644 --- a/compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java @@ -21,9 +21,9 @@ import java.io.Serializable; import com.vaadin.data.Binder; import com.vaadin.server.AbstractErrorMessage; import com.vaadin.server.ErrorMessage; -import com.vaadin.server.ErrorMessage.ErrorLevel; import com.vaadin.server.ErrorMessageProducer; import com.vaadin.server.UserError; +import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.v7.data.Validator.InvalidValueException; /** diff --git a/compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java b/compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java index f226622359..f13a01a5b5 100644 --- a/compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java +++ b/compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java @@ -22,10 +22,10 @@ import com.vaadin.data.Binder; import com.vaadin.server.AbstractErrorMessage; import com.vaadin.server.AbstractErrorMessage.ContentMode; import com.vaadin.server.ErrorMessage; -import com.vaadin.server.ErrorMessage.ErrorLevel; import com.vaadin.server.ErrorMessageProducer; import com.vaadin.server.UserError; import com.vaadin.server.VaadinServlet; +import com.vaadin.shared.ui.ErrorLevel; /** * Interface that implements a method for validating if an {@link Object} is diff --git a/compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java b/compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java index 9b64d1e6f8..6cd7323cd9 100644 --- a/compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java +++ b/compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java @@ -58,6 +58,7 @@ import com.vaadin.server.VaadinSession; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.Registration; import com.vaadin.shared.data.sort.SortDirection; +import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.shared.util.SharedUtil; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Component; diff --git a/compatibility-server/src/test/java/com/vaadin/v7/ui/AbstractLegacyComponentDeclarativeTest.java b/compatibility-server/src/test/java/com/vaadin/v7/ui/AbstractLegacyComponentDeclarativeTest.java index 5a26833169..938e2d61de 100644 --- a/compatibility-server/src/test/java/com/vaadin/v7/ui/AbstractLegacyComponentDeclarativeTest.java +++ b/compatibility-server/src/test/java/com/vaadin/v7/ui/AbstractLegacyComponentDeclarativeTest.java @@ -29,12 +29,12 @@ import org.jsoup.parser.Tag; import org.junit.Before; import org.junit.Test; -import com.vaadin.server.ErrorMessage.ErrorLevel; import com.vaadin.server.ExternalResource; import com.vaadin.server.FileResource; import com.vaadin.server.Responsive; import com.vaadin.server.ThemeResource; import com.vaadin.server.UserError; +import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.tests.design.DeclarativeTestBase; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Label; diff --git a/server/src/main/java/com/vaadin/server/AbstractErrorMessage.java b/server/src/main/java/com/vaadin/server/AbstractErrorMessage.java index cad1dc425d..b7e439244e 100644 --- a/server/src/main/java/com/vaadin/server/AbstractErrorMessage.java +++ b/server/src/main/java/com/vaadin/server/AbstractErrorMessage.java @@ -21,6 +21,8 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.List; +import com.vaadin.shared.ui.ErrorLevel; + /** * Base class for component error messages. * diff --git a/server/src/main/java/com/vaadin/server/CompositeErrorMessage.java b/server/src/main/java/com/vaadin/server/CompositeErrorMessage.java index 6d6a775a1b..510ef4ed00 100644 --- a/server/src/main/java/com/vaadin/server/CompositeErrorMessage.java +++ b/server/src/main/java/com/vaadin/server/CompositeErrorMessage.java @@ -19,6 +19,8 @@ package com.vaadin.server; import java.util.Collection; import java.util.Iterator; +import com.vaadin.shared.ui.ErrorLevel; + /** * Class for combining multiple error messages together. * @@ -37,7 +39,7 @@ public class CompositeErrorMessage extends AbstractErrorMessage { */ public CompositeErrorMessage(ErrorMessage... errorMessages) { super(null); - setErrorLevel(ErrorLevel.INFORMATION); + setErrorLevel(ErrorLevel.INFO); for (ErrorMessage errorMessage : errorMessages) { addErrorMessage(errorMessage); @@ -60,7 +62,7 @@ public class CompositeErrorMessage extends AbstractErrorMessage { public CompositeErrorMessage( Collection<? extends ErrorMessage> errorMessages) { super(null); - setErrorLevel(ErrorLevel.INFORMATION); + setErrorLevel(ErrorLevel.INFO); for (ErrorMessage errorMessage : errorMessages) { addErrorMessage(errorMessage); diff --git a/server/src/main/java/com/vaadin/server/ErrorMessage.java b/server/src/main/java/com/vaadin/server/ErrorMessage.java index f4030ed4c9..8095a5afdd 100644 --- a/server/src/main/java/com/vaadin/server/ErrorMessage.java +++ b/server/src/main/java/com/vaadin/server/ErrorMessage.java @@ -18,6 +18,8 @@ package com.vaadin.server; import java.io.Serializable; +import com.vaadin.shared.ui.ErrorLevel; + /** * Interface for rendering error messages to terminal. All the visible errors * shown to user must implement this interface. @@ -27,66 +29,11 @@ import java.io.Serializable; */ public interface ErrorMessage extends Serializable { - public enum ErrorLevel { - /** - * Error code for informational messages. - */ - INFORMATION("info", 0), - /** - * Error code for warning messages. - */ - WARNING("warning", 1), - /** - * Error code for regular error messages. - */ - ERROR("error", 2), - /** - * Error code for critical error messages. - */ - CRITICAL("critical", 3), - /** - * Error code for system errors and bugs. - */ - SYSTEMERROR("system", 4); - - String text; - int errorLevel; - - private ErrorLevel(String text, int errorLevel) { - this.text = text; - this.errorLevel = errorLevel; - } - - /** - * Textual representation for server-client communication of level - * - * @return String for error severity - */ - public String getText() { - return text; - } - - /** - * Integer representation of error severity for comparison - * - * @return integer for error severity - */ - public int intValue() { - return errorLevel; - } - - @Override - public String toString() { - return text; - } - - } - /** - * @deprecated As of 7.0, use {@link ErrorLevel#SYSTEMERROR} instead   + * @deprecated As of 7.0, use {@link ErrorLevel#SYSTEM} instead   */ @Deprecated - public static final ErrorLevel SYSTEMERROR = ErrorLevel.SYSTEMERROR; + public static final ErrorLevel SYSTEMERROR = ErrorLevel.SYSTEM; /** * @deprecated As of 7.0, use {@link ErrorLevel#CRITICAL} instead   @@ -108,10 +55,10 @@ public interface ErrorMessage extends Serializable { public static final ErrorLevel WARNING = ErrorLevel.WARNING; /** - * @deprecated As of 7.0, use {@link ErrorLevel#INFORMATION} instead   + * @deprecated As of 7.0, use {@link ErrorLevel#INFO} instead   */ @Deprecated - public static final ErrorLevel INFORMATION = ErrorLevel.INFORMATION; + public static final ErrorLevel INFORMATION = ErrorLevel.INFO; /** * Gets the errors level. diff --git a/server/src/main/java/com/vaadin/server/SystemError.java b/server/src/main/java/com/vaadin/server/SystemError.java index 734b4862a8..151021d1f8 100644 --- a/server/src/main/java/com/vaadin/server/SystemError.java +++ b/server/src/main/java/com/vaadin/server/SystemError.java @@ -16,6 +16,8 @@ package com.vaadin.server; +import com.vaadin.shared.ui.ErrorLevel; + /** * <code>SystemError</code> is an error message for a problem caused by error in * system, not the user application code. The system error can contain technical @@ -39,7 +41,7 @@ public class SystemError extends AbstractErrorMessage { */ public SystemError(String message) { super(message); - setErrorLevel(ErrorLevel.SYSTEMERROR); + setErrorLevel(ErrorLevel.SYSTEM); setMode(ContentMode.HTML); setMessage(getHtmlMessage()); } diff --git a/server/src/main/java/com/vaadin/server/UserError.java b/server/src/main/java/com/vaadin/server/UserError.java index b017c9e1f9..636e98a02f 100644 --- a/server/src/main/java/com/vaadin/server/UserError.java +++ b/server/src/main/java/com/vaadin/server/UserError.java @@ -16,6 +16,8 @@ package com.vaadin.server; +import com.vaadin.shared.ui.ErrorLevel; + /** * <code>UserError</code> is a controlled error occurred in application. User * errors are occur in normal usage of the application and guide the user. diff --git a/server/src/main/java/com/vaadin/ui/AbstractComponent.java b/server/src/main/java/com/vaadin/ui/AbstractComponent.java index a0bb648ffb..f74f2141da 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractComponent.java +++ b/server/src/main/java/com/vaadin/ui/AbstractComponent.java @@ -45,7 +45,6 @@ import com.vaadin.server.AbstractClientConnector; import com.vaadin.server.ClientConnector; import com.vaadin.server.ComponentSizeValidator; import com.vaadin.server.ErrorMessage; -import com.vaadin.server.ErrorMessage.ErrorLevel; import com.vaadin.server.Extension; import com.vaadin.server.Resource; import com.vaadin.server.Responsive; @@ -62,6 +61,7 @@ import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.Registration; import com.vaadin.shared.ui.ComponentStateUtil; import com.vaadin.shared.ui.ContentMode; +import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.shared.util.SharedUtil; import com.vaadin.ui.declarative.DesignAttributeHandler; import com.vaadin.ui.declarative.DesignContext; @@ -723,8 +723,10 @@ public abstract class AbstractComponent extends AbstractClientConnector ErrorMessage error = getErrorMessage(); if (null != error) { getState().errorMessage = error.getFormattedHtmlMessage(); + getState().errorLevel = error.getErrorLevel(); } else { getState().errorMessage = null; + getState().errorLevel = null; } } diff --git a/server/src/main/java/com/vaadin/ui/TabSheet.java b/server/src/main/java/com/vaadin/ui/TabSheet.java index 385c6b5f5c..ac3a22eb41 100644 --- a/server/src/main/java/com/vaadin/ui/TabSheet.java +++ b/server/src/main/java/com/vaadin/ui/TabSheet.java @@ -1314,9 +1314,15 @@ public class TabSheet extends AbstractComponentContainer public void setComponentError(ErrorMessage componentError) { this.componentError = componentError; - String formattedHtmlMessage = componentError != null - ? componentError.getFormattedHtmlMessage() : null; - tabState.componentError = formattedHtmlMessage; + if (componentError != null) { + tabState.componentError = componentError + .getFormattedHtmlMessage(); + tabState.componentErrorLevel = componentError.getErrorLevel(); + } else { + tabState.componentError = null; + tabState.componentErrorLevel = null; + } + markAsDirty(); } diff --git a/server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTest.java b/server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTest.java index 018aa25cd4..b2a32efaa0 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTest.java +++ b/server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTest.java @@ -28,13 +28,13 @@ import org.jsoup.parser.Tag; import org.junit.Before; import org.junit.Test; -import com.vaadin.server.ErrorMessage.ErrorLevel; import com.vaadin.shared.ui.ContentMode; import com.vaadin.server.ExternalResource; import com.vaadin.server.FileResource; import com.vaadin.server.Responsive; import com.vaadin.server.ThemeResource; import com.vaadin.server.UserError; +import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.tests.design.DeclarativeTestBase; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.Button; diff --git a/server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTestBase.java b/server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTestBase.java index 84c2534f84..48d9646c37 100644 --- a/server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTestBase.java +++ b/server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTestBase.java @@ -24,11 +24,11 @@ import java.util.Locale; import org.junit.Test; -import com.vaadin.server.ErrorMessage.ErrorLevel; import com.vaadin.server.ExternalResource; import com.vaadin.server.FileResource; import com.vaadin.server.ThemeResource; import com.vaadin.server.UserError; +import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.tests.design.DeclarativeTestBase; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.declarative.DesignContext; diff --git a/shared/src/main/java/com/vaadin/shared/AbstractComponentState.java b/shared/src/main/java/com/vaadin/shared/AbstractComponentState.java index 81f808f676..9b949111a7 100644 --- a/shared/src/main/java/com/vaadin/shared/AbstractComponentState.java +++ b/shared/src/main/java/com/vaadin/shared/AbstractComponentState.java @@ -21,6 +21,7 @@ import java.util.List; import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.communication.SharedState; import com.vaadin.shared.ui.ContentMode; +import com.vaadin.shared.ui.ErrorLevel; /** * Default shared state implementation for AbstractComponent. @@ -43,9 +44,15 @@ public class AbstractComponentState extends SharedState { public String id = null; public String primaryStyleName = null; - // HTML formatted error message for the component - // TODO this could be an object with more information, but currently the UI - // only uses the message + /** HTML formatted error message for the component */ public String errorMessage = null; + + /** + * Level of error + * + * @since 8.2 + */ + public ErrorLevel errorLevel = null; + public boolean captionAsHtml = false; } diff --git a/shared/src/main/java/com/vaadin/shared/ui/ErrorLevel.java b/shared/src/main/java/com/vaadin/shared/ui/ErrorLevel.java new file mode 100644 index 0000000000..fe216fb878 --- /dev/null +++ b/shared/src/main/java/com/vaadin/shared/ui/ErrorLevel.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2016 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.shared.ui; + +/** + * Represents the error levels displayed on components. + * @author Vaadin Ltd + * @since + */ +public enum ErrorLevel { + + /** + * Error level for informational messages. + */ + INFO, + + /** + * Error level for warning messages. + */ + WARNING, + + /** + * Error level for regular messages. + */ + ERROR, + + /** + * Error level for critical messages. + */ + CRITICAL, + + /** + * Error level for system errors and bugs. + */ + SYSTEM; + + /** + * Integer representation of error severity for comparison + * + * @return integer for error severity + */ + public int intValue() { + return ordinal(); + } +} diff --git a/shared/src/main/java/com/vaadin/shared/ui/tabsheet/TabState.java b/shared/src/main/java/com/vaadin/shared/ui/tabsheet/TabState.java index 763f2cf20f..b337d4f063 100644 --- a/shared/src/main/java/com/vaadin/shared/ui/tabsheet/TabState.java +++ b/shared/src/main/java/com/vaadin/shared/ui/tabsheet/TabState.java @@ -19,6 +19,8 @@ import java.io.Serializable; import com.vaadin.shared.ui.ContentMode; +import com.vaadin.shared.ui.ErrorLevel; + /** * Shared state of a single tab in a Tabsheet or an Accordion. * @@ -36,6 +38,13 @@ public class TabState implements Serializable { public String styleName; public String key; public String componentError; + + /** + * Represents the level of error on a tab. + * + * @since 8.2 + */ + public ErrorLevel componentErrorLevel; public String id; public String iconAltText; diff --git a/tests/screenshots b/tests/screenshots -Subproject 3a4a26065d36ac5fb706c159f1dd757fb52bf8e +Subproject 37f67cd836df7d34469f55298bb167696338f2a diff --git a/themes/src/main/themes/VAADIN/themes/valo/components/_combobox.scss b/themes/src/main/themes/VAADIN/themes/valo/components/_combobox.scss index 4069415985..8e45fc4afc 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/components/_combobox.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/components/_combobox.scss @@ -35,6 +35,61 @@ } } + .#{$primary-stylename}-error-info { + .#{$primary-stylename}-input { + @include valo-textfield-error-level-info-style; + } + + .#{$primary-stylename}-button { + color: $v-error-indicator-level-info-color; + border-color: $v-error-indicator-level-info-color; + } + } + + .#{$primary-stylename}-error-warning { + .#{$primary-stylename}-input { + @include valo-textfield-error-level-warning-style; + } + + .#{$primary-stylename}-button { + color: $v-error-indicator-level-warning-color; + border-color: $v-error-indicator-level-warning-color; + } + } + + .#{$primary-stylename}-error-error { + .#{$primary-stylename}-input { + @include valo-textfield-error-level-error-style; + } + + .#{$primary-stylename}-button { + color: $v-error-indicator-level-error-color; + border-color: $v-error-indicator-level-error-color; + } + } + + .#{$primary-stylename}-error-critical { + .#{$primary-stylename}-input { + @include valo-textfield-error-level-critical-style; + } + + .#{$primary-stylename}-button { + color: $v-error-indicator-level-critical-color; + border-color: $v-error-indicator-level-critical-color; + } + } + + .#{$primary-stylename}-error-system { + .#{$primary-stylename}-input { + @include valo-textfield-error-level-system-style; + } + + .#{$primary-stylename}-button { + color: $v-error-indicator-level-system-color; + border-color: $v-error-indicator-level-system-color; + } + } + .#{$primary-stylename}-suggestpopup { @include valo-combobox-popup-style; } diff --git a/themes/src/main/themes/VAADIN/themes/valo/components/_datefield.scss b/themes/src/main/themes/VAADIN/themes/valo/components/_datefield.scss index bfe1e33743..e92c9ce436 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/components/_datefield.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/components/_datefield.scss @@ -25,6 +25,61 @@ } } + .#{$primary-stylename}-error-info { + .#{$primary-stylename}-textfield { + @include valo-textfield-error-level-info-style; + } + + .#{$primary-stylename}-button { + color: $v-error-indicator-level-info-color; + border-color: $v-error-indicator-level-info-color; + } + } + + .#{$primary-stylename}-error-warning { + .#{$primary-stylename}-textfield { + @include valo-textfield-error-level-warning-style; + } + + .#{$primary-stylename}-button { + color: $v-error-indicator-level-warning-color; + border-color: $v-error-indicator-level-warning-color; + } + } + + .#{$primary-stylename}-error-error { + .#{$primary-stylename}-textfield { + @include valo-textfield-error-level-error-style; + } + + .#{$primary-stylename}-button { + color: $v-error-indicator-level-error-color; + border-color: $v-error-indicator-level-error-color; + } + } + + .#{$primary-stylename}-error-critical { + .#{$primary-stylename}-textfield { + @include valo-textfield-error-level-critical-style; + } + + .#{$primary-stylename}-button { + color: $v-error-indicator-level-critical-color; + border-color: $v-error-indicator-level-critical-color; + } + } + + .#{$primary-stylename}-error-system { + .#{$primary-stylename}-textfield { + @include valo-textfield-error-level-system-style; + } + + .#{$primary-stylename}-button { + color: $v-error-indicator-level-system-color; + border-color: $v-error-indicator-level-system-color; + } + } + // Different widths for different resolutions .#{$primary-stylename}-full { width: round($v-font-size * 15); diff --git a/themes/src/main/themes/VAADIN/themes/valo/components/_textfield.scss b/themes/src/main/themes/VAADIN/themes/valo/components/_textfield.scss index 5a62be5dbc..91fad01744 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/components/_textfield.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/components/_textfield.scss @@ -70,6 +70,25 @@ $v-textfield-disabled-opacity: $v-disabled-opacity !default; @include valo-textfield-error-style; } + .#{$primary-stylename}-error-info { + @include valo-textfield-error-level-info-style; + } + + .#{$primary-stylename}-error-warning { + @include valo-textfield-error-level-warning-style; + } + + .#{$primary-stylename}-error-error { + @include valo-textfield-error-level-error-style; + } + + .#{$primary-stylename}-error-critical { + @include valo-textfield-error-level-critical-style; + } + + .#{$primary-stylename}-error-system { + @include valo-textfield-error-level-system-style; + } @if $include-additional-styles { .#{$primary-stylename}-borderless { @@ -319,13 +338,58 @@ $v-textfield-disabled-opacity: $v-disabled-opacity !default; * * @group textfield */ -@mixin valo-textfield-error-style { - border-color: $v-error-indicator-color !important; - $bg: scale-color($v-error-indicator-color, $lightness: 98%); +@mixin valo-textfield-error-style($indicator-color: $v-error-indicator-color) { + border-color: $indicator-color !important; + $bg: scale-color($indicator-color, $lightness: 98%); background: $bg; color: valo-font-color($bg); } +/** + * Outputs the styles for a text field error state with error level 'info'. + * + * @group textfield + */ +@mixin valo-textfield-error-level-info-style { + @include valo-textfield-error-style($v-error-indicator-level-info-color); +} + +/** + * Outputs the styles for a text field error state with error level 'warning'. + * + * @group textfield + */ +@mixin valo-textfield-error-level-warning-style { + @include valo-textfield-error-style($v-error-indicator-level-warning-color); +} + +/** + * Outputs the styles for a text field error state with error level 'error'. + * + * @group textfield + */ +@mixin valo-textfield-error-level-error-style { + @include valo-textfield-error-style($v-error-indicator-level-error-color); +} + +/** + * Outputs the styles for a text field error state with error level 'critical'. + * + * @group textfield + */ +@mixin valo-textfield-error-level-critical-style { + @include valo-textfield-error-style($v-error-indicator-level-critical-color); +} + +/** + * Outputs the styles for a text field error state with error level 'system'. + * + * @group textfield + */ +@mixin valo-textfield-error-level-system-style { + @include valo-textfield-error-style($v-error-indicator-level-system-color); +} + /** * Outputs the selectors and styles for an inline-icon style for a text field. Included indipendently (i.e. not enclosed with a parent text field selector). diff --git a/themes/src/main/themes/VAADIN/themes/valo/components/_twincolselect.scss b/themes/src/main/themes/VAADIN/themes/valo/components/_twincolselect.scss index 1d9a7e773e..8d220292e7 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/components/_twincolselect.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/components/_twincolselect.scss @@ -85,6 +85,40 @@ } } + .#{$primary-stylename}-error-info { + .#{$primary-stylename}-options, + .#{$primary-stylename}-selections { + @include valo-textfield-error-level-info-style; + } + } + + .#{$primary-stylename}-error-warning { + .#{$primary-stylename}-options, + .#{$primary-stylename}-selections { + @include valo-textfield-error-level-warning-style; + } + } + + .#{$primary-stylename}-error-error { + .#{$primary-stylename}-options, + .#{$primary-stylename}-selections { + @include valo-textfield-error-level-error-style; + } + } + + .#{$primary-stylename}-error-critical { + .#{$primary-stylename}-options, + .#{$primary-stylename}-selections { + @include valo-textfield-error-level-critical-style; + } + } + + .#{$primary-stylename}-error-system { + .#{$primary-stylename}-options, + .#{$primary-stylename}-selections { + @include valo-textfield-error-level-system-style; + } + } } diff --git a/themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss b/themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss index ecd8e1a59b..99fbd360b1 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss @@ -313,6 +313,26 @@ $valo-shared-pathPrefix: null; @include valo-error-indicator-style; } + .v-errorindicator-info { + @include valo-error-indicator-style($indicator-color: $v-error-indicator-level-info-color); + } + + .v-errorindicator-warning { + @include valo-error-indicator-style($indicator-color: $v-error-indicator-level-warning-color); + } + + .v-errorindicator-error { + @include valo-error-indicator-style($indicator-color: $v-error-indicator-level-error-color); + } + + .v-errorindicator-critical { + @include valo-error-indicator-style($indicator-color: $v-error-indicator-level-critical-color); + } + + .v-errorindicator-system { + @include valo-error-indicator-style($indicator-color: $v-error-indicator-level-system-color); + } + .v-required-field-indicator { color: $v-required-field-indicator-color; padding: 0 .2em; @@ -366,8 +386,8 @@ $valo-shared-pathPrefix: null; * * @requires {mixin} valo-error-indicator-icon-style by default */ -@mixin valo-error-indicator-style ($is-pseudo-element: false) { - color: $v-error-indicator-color; +@mixin valo-error-indicator-style ($is-pseudo-element: false, $indicator-color: $v-error-indicator-color) { + color: $indicator-color; font-weight: 600; width: ceil($v-unit-size/2); text-align: center; diff --git a/themes/src/main/themes/VAADIN/themes/valo/shared/_tooltip.scss b/themes/src/main/themes/VAADIN/themes/valo/shared/_tooltip.scss index cb3824d26f..99c453b16e 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/shared/_tooltip.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/shared/_tooltip.scss @@ -63,6 +63,46 @@ $v-tooltip-error-message-background-color: #fff !default; $v-tooltip-error-message-font-color: $v-error-indicator-color !default; /** + * The font color for error tooltips for level 'info'. + * + * @type color + * @group tooltip + */ +$v-tooltip-error-message-level-info-font-color: $v-error-indicator-level-info-color !default; + +/** + * The font color for error tooltips for level 'warning'. + * + * @type color + * @group tooltip + */ +$v-tooltip-error-message-level-warning-font-color: $v-error-indicator-level-warning-color !default; + +/** + * The font color for error tooltips for level 'error'. + * + * @type color + * @group tooltip + */ +$v-tooltip-error-message-level-error-font-color: $v-error-indicator-level-error-color !default; + +/** + * The font color for error tooltips for level 'critical'. + * + * @type color + * @group tooltip + */ +$v-tooltip-error-message-level-critical-font-color: $v-error-indicator-level-critical-color !default; + +/** + * The font color for error tooltips for level 'system'. + * + * @type color + * @group tooltip + */ +$v-tooltip-error-message-level-system-font-color: $v-error-indicator-level-system-color !default; + +/** * The corner radius for tooltips. * * @type size @@ -100,6 +140,26 @@ $v-tooltip-border-radius: $v-border-radius - 1px !default; } } + .v-errormessage-info { + color: $v-tooltip-error-message-level-info-font-color; + } + + .v-errormessage-warning { + color: $v-tooltip-error-message-level-warning-font-color; + } + + .v-errormessage-error { + color: $v-tooltip-error-message-level-error-font-color; + } + + .v-errormessage-critical { + color: $v-tooltip-error-message-level-critical-font-color; + } + + .v-errormessage-system { + color: $v-tooltip-error-message-level-system-font-color; + } + .v-tooltip-text { max-height: 10em; overflow: auto; diff --git a/themes/src/main/themes/VAADIN/themes/valo/shared/_variables.scss b/themes/src/main/themes/VAADIN/themes/valo/shared/_variables.scss index 3237018087..51f6f73350 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/shared/_variables.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/shared/_variables.scss @@ -207,13 +207,53 @@ $v-disabled-opacity: 0.5 !default; $v-selection-color: $v-focus-color !default; /** + * Color of the component error indication for 'info' error level. + + * @group color + * @type color + */ +$v-error-indicator-level-info-color: #00a7f5 !default; + +/** + * Color of the component error indication for 'warning' error level. + + * @group color + * @type color + */ +$v-error-indicator-level-warning-color: #fc9c00 !default; + +/** + * Color of the component error indication for 'error' error level. + + * @group color + * @type color + */ +$v-error-indicator-level-error-color: #ed473b !default; + +/** + * Color of the component error indication for 'critical' error level. + + * @group color + * @type color + */ +$v-error-indicator-level-critical-color: #fa007d !default; + +/** + * Color of the component error indication for 'system' error level. + + * @group color + * @type color + */ +$v-error-indicator-level-system-color: #bb00ff !default; + +/** * Color of the component error indicator and other error indications, such as the * error style notification. * * @group color * @type color */ -$v-error-indicator-color: #ed473b !default; +$v-error-indicator-color: $v-error-indicator-level-error-color !default; /** * Color of the required indicator in field components. diff --git a/uitest/src/main/java/com/vaadin/tests/components/ErrorLevels.java b/uitest/src/main/java/com/vaadin/tests/components/ErrorLevels.java new file mode 100644 index 0000000000..9ab5ca6f0b --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/components/ErrorLevels.java @@ -0,0 +1,210 @@ +package com.vaadin.tests.components; + +import java.util.Arrays; + +import com.vaadin.annotations.Theme; +import com.vaadin.server.AbstractErrorMessage; +import com.vaadin.server.ErrorMessage; +import com.vaadin.server.ExternalResource; +import com.vaadin.server.UserError; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.ui.ErrorLevel; +import com.vaadin.ui.Accordion; +import com.vaadin.ui.Button; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.DateField; +import com.vaadin.ui.FormLayout; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.Link; +import com.vaadin.ui.NativeButton; +import com.vaadin.ui.Panel; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.TextField; +import com.vaadin.ui.TwinColSelect; +import com.vaadin.ui.themes.ValoTheme; + +@Theme("valo") +public class ErrorLevels extends AbstractTestUI { + + private ComboBox<ErrorLevel> errorLevels; + private Button button; + private Button borderlessButton; + private Link link; + private ComboBox<String> comboBox; + private TextField textField; + private TextField textFieldBorderless; + private TabSheet tabSheet; + private Accordion accordion; + private CheckBox checkBox; + private NativeButton nativeButton; + private FormLayout formLayout; + private TextField formLayoutTextField; + private Panel panel; + private DateField dateField; + private TwinColSelect twinColSelect; + + private com.vaadin.v7.ui.ComboBox comboBoxCompat; + private com.vaadin.v7.ui.TextField textFieldCompat; + private com.vaadin.v7.ui.CheckBox checkBoxCompat; + private com.vaadin.v7.ui.DateField dateFieldCompat; + private com.vaadin.v7.ui.TwinColSelect twinColSelectCompat; + + @Override + protected void setup(VaadinRequest request) { + + errorLevels = new ComboBox<>("Error level", + Arrays.asList(ErrorLevel.values())); + errorLevels.setEmptySelectionAllowed(false); + errorLevels.setValue(ErrorLevel.ERROR); + errorLevels.addValueChangeListener(event -> setErrorMessages()); + addComponent(errorLevels); + + Label subtitle = new Label("Components"); + subtitle.setStyleName(ValoTheme.LABEL_H3); + addComponent(subtitle); + + // Button + button = new Button("Button"); + + borderlessButton = new Button("Borderless button"); + borderlessButton.setStyleName(ValoTheme.BUTTON_BORDERLESS); + + addComponent(new HorizontalLayout(button, borderlessButton)); + + // Native button + nativeButton = new NativeButton("Native button"); + addComponent(nativeButton); + + // Link + link = new Link("Link", new ExternalResource("#")); + addComponent(link); + + // Combo box + comboBox = new ComboBox<>("Combo box"); + addComponent(comboBox); + + // Text field + textField = new TextField("Text field"); + textField.setValue("text"); + + textFieldBorderless = new TextField("Borderless text field"); + textFieldBorderless.setStyleName(ValoTheme.TEXTFIELD_BORDERLESS); + textFieldBorderless.setValue("text"); + + addComponent(new HorizontalLayout(textField, textFieldBorderless)); + + // Date field + dateField = new DateField("Date field"); + addComponent(dateField); + + // Check box + checkBox = new CheckBox("Check box"); + addComponent(checkBox); + + // Tab sheet + tabSheet = new TabSheet(); + tabSheet.addTab(new Label("Label1"), "Tab1"); + tabSheet.addTab(new Label("Label2"), "Tab2"); + tabSheet.setWidth("400px"); + addComponent(tabSheet); + + // Accordion + accordion = new Accordion(); + accordion.addTab(new Label("Label1"), "Tab1"); + accordion.addTab(new Label("Label2"), "Tab2"); + accordion.setWidth("400px"); + addComponent(accordion); + + // Form layout + formLayout = new FormLayout(); + formLayout.setWidth("400px"); + + formLayoutTextField = new TextField("Form layout text field"); + formLayout.addComponent(formLayoutTextField); + + addComponent(formLayout); + + // Panel + panel = new Panel(); + panel.setContent(new Label("Panel")); + panel.setWidth("400px"); + addComponent(panel); + + // TwinColSelect + twinColSelect = new TwinColSelect("Twin col select"); + addComponent(twinColSelect); + + Label subtitleCompat = new Label("Compatibility components"); + subtitleCompat.setStyleName(ValoTheme.LABEL_H3); + addComponent(subtitleCompat); + + // Compatibility combo box + comboBoxCompat = new com.vaadin.v7.ui.ComboBox( + "Compatibility combo box"); + addComponent(comboBoxCompat); + + // Compatibility text field + textFieldCompat = new com.vaadin.v7.ui.TextField( + "Compatibility text field"); + textFieldCompat.setValue("text"); + + // Compatibility check box + checkBoxCompat = new com.vaadin.v7.ui.CheckBox("Check box"); + addComponent(checkBoxCompat); + + // Compatibility date field + dateFieldCompat = new com.vaadin.v7.ui.DateField("Date field"); + addComponent(dateFieldCompat); + + // Compatibility twin col select + twinColSelectCompat = new com.vaadin.v7.ui.TwinColSelect( + "Twin col select"); + addComponent(twinColSelectCompat); + + setErrorMessages(); + + getLayout().setSpacing(true); + } + + private void setErrorMessages() { + button.setComponentError(createErrorMessage("Button error")); + borderlessButton.setComponentError( + createErrorMessage("Borderless button error")); + link.setComponentError(createErrorMessage("Link error")); + comboBox.setComponentError(createErrorMessage("ComboBox error")); + textField.setComponentError(createErrorMessage("Text field error")); + textFieldBorderless.setComponentError( + createErrorMessage("Borderless text field error")); + tabSheet.setComponentError(createErrorMessage("Tab sheet error")); + tabSheet.getTab(0).setComponentError(createErrorMessage("Tab error")); + accordion.setComponentError(createErrorMessage("Accordion error")); + accordion.getTab(0).setComponentError(createErrorMessage("Tab error")); + checkBox.setComponentError(createErrorMessage("Check box error")); + nativeButton + .setComponentError(createErrorMessage("Native button error")); + formLayout.setComponentError(createErrorMessage("Form layout error")); + formLayoutTextField.setComponentError( + createErrorMessage("Form layout text field error")); + panel.setComponentError(createErrorMessage("Panel error")); + dateField.setComponentError(createErrorMessage("Date field error")); + twinColSelect + .setComponentError(createErrorMessage("Twin col select error")); + comboBoxCompat.setComponentError( + createErrorMessage("Compatibility combo box error")); + textFieldCompat.setComponentError( + createErrorMessage("Compatibility text field error")); + checkBoxCompat.setComponentError( + createErrorMessage("Compatibility check box error")); + dateFieldCompat.setComponentError( + createErrorMessage("Compatibility date field error")); + twinColSelectCompat.setComponentError( + createErrorMessage("Compatibility twin col select error")); + } + + private ErrorMessage createErrorMessage(String text) { + return new UserError(text, AbstractErrorMessage.ContentMode.TEXT, + errorLevels.getValue()); + } +} diff --git a/uitest/src/main/java/com/vaadin/tests/themes/valo/CommonParts.java b/uitest/src/main/java/com/vaadin/tests/themes/valo/CommonParts.java index 6d7a67cfa8..4c83430832 100644 --- a/uitest/src/main/java/com/vaadin/tests/themes/valo/CommonParts.java +++ b/uitest/src/main/java/com/vaadin/tests/themes/valo/CommonParts.java @@ -20,11 +20,11 @@ import com.vaadin.icons.VaadinIcons; import com.vaadin.navigator.View; import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; import com.vaadin.server.AbstractErrorMessage; -import com.vaadin.server.ErrorMessage.ErrorLevel; import com.vaadin.server.Page; import com.vaadin.server.UserError; import com.vaadin.shared.Position; import com.vaadin.shared.ui.ContentMode; +import com.vaadin.shared.ui.ErrorLevel; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; diff --git a/uitest/src/test/java/com/vaadin/tests/components/ErrorLevelsTest.java b/uitest/src/test/java/com/vaadin/tests/components/ErrorLevelsTest.java new file mode 100644 index 0000000000..750545ce89 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/ErrorLevelsTest.java @@ -0,0 +1,160 @@ +package com.vaadin.tests.components; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; + +import com.vaadin.client.StyleConstants; +import com.vaadin.shared.ui.ErrorLevel; +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.AccordionElement; +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.CheckBoxElement; +import com.vaadin.testbench.elements.ComboBoxElement; +import com.vaadin.testbench.elements.DateFieldElement; +import com.vaadin.testbench.elements.FormLayoutElement; +import com.vaadin.testbench.elements.LinkElement; +import com.vaadin.testbench.elements.NativeButtonElement; +import com.vaadin.testbench.elements.PanelElement; +import com.vaadin.testbench.elements.TabSheetElement; +import com.vaadin.testbench.elements.TwinColSelectElement; +import com.vaadin.testbench.parallel.BrowserUtil; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class ErrorLevelsTest extends SingleBrowserTest { + + private ComboBoxElement errorLevelSelector; + + @Override + public void setup() throws Exception { + super.setup(); + openTestURL(); + + errorLevelSelector = $(ComboBoxElement.class).first(); + } + + @Test + public void testErrorIndicatorsClassName() { + ErrorLevel errorLevel = ErrorLevel.WARNING; + selectErrorLevel(errorLevel); + + List<WebElement> errorIndicators = findElements( + By.className(StyleConstants.STYLE_NAME_ERROR_INDICATOR)); + for (WebElement errorIndicator : errorIndicators) { + assertHasRightClassNames(errorIndicator, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel); + } + } + + @Test + public void testComponentsClassName() { + ErrorLevel errorLevel = ErrorLevel.WARNING; + selectErrorLevel(errorLevel); + + // Button + ButtonElement buttonElement = $(ButtonElement.class).first(); + assertHasRightClassNames(buttonElement, "v-button-error", errorLevel); + + // Native button + NativeButtonElement nativeButtonElement = $(NativeButtonElement.class) + .first(); + assertHasRightClassNames(nativeButtonElement, "v-nativebutton-error", + errorLevel); + + // Link + LinkElement linkElement = $(LinkElement.class).first(); + assertHasRightClassNames(linkElement, "v-link-error", errorLevel); + + // Combo box + ComboBoxElement comboBoxElement = $(ComboBoxElement.class).get(1); + assertHasRightClassNames(comboBoxElement, "v-filterselect-error", + errorLevel); + + // Date field + DateFieldElement dateFieldElement = $(DateFieldElement.class).first(); + assertHasRightClassNames(dateFieldElement, "v-datefield-error", + errorLevel); + + // Checkbox + CheckBoxElement checkBoxElement = $(CheckBoxElement.class).first(); + assertHasRightClassNames(checkBoxElement, "v-checkbox-error", + errorLevel); + + // Tab sheet + TabSheetElement tabSheetElement = $(TabSheetElement.class).first(); + assertHasRightClassNames(tabSheetElement, "v-tabsheet-error", + errorLevel); + + // Accordion + AccordionElement accordionElement = $(AccordionElement.class).first(); + assertHasRightClassNames(accordionElement, "v-accordion-error", + errorLevel); + + // Form layout + FormLayoutElement formLayoutElement = $(FormLayoutElement.class) + .first(); + assertHasRightClassNames(formLayoutElement, "v-formlayout-error", + errorLevel); + + // Panel + PanelElement panelElement = $(PanelElement.class).first(); + assertHasRightClassNames(panelElement, "v-panel-error", errorLevel); + + // Twin col select + TwinColSelectElement twinColSelectElement = $( + TwinColSelectElement.class).first(); + assertHasRightClassNames(twinColSelectElement, "v-select-twincol-error", + errorLevel); + } + + private void assertHasRightClassNames(WebElement element, String prefix, + ErrorLevel errorLevel) { + Assert.assertTrue("Element must have only one error level class name", + containsCorrectErrorLevelClassNameOnly(element, prefix, + errorLevel)); + } + + private boolean containsCorrectErrorLevelClassNameOnly(WebElement element, + String prefix, ErrorLevel errorLevel) { + List<String> classNames = new ArrayList<String>( + Arrays.asList(element.getAttribute("class").split(" "))); + classNames.retainAll(getErrorLevelClassNames(prefix, + Arrays.asList(ErrorLevel.values()))); + return classNames.size() == 1 && classNames + .contains(getErrorLevelClassName(prefix, errorLevel)); + } + + private String getErrorLevelClassName(String prefix, + ErrorLevel errorLevel) { + return prefix + "-" + errorLevel.toString().toLowerCase(); + } + + private List<String> getErrorLevelClassNames(String prefix, + Collection<ErrorLevel> errorLevels) { + List<String> classNames = new ArrayList<String>(errorLevels.size()); + for (ErrorLevel errorLevel : errorLevels) { + classNames.add(getErrorLevelClassName(prefix, errorLevel)); + } + return classNames; + } + + private void selectErrorLevel(ErrorLevel errorLevel) { + errorLevelSelector.clear(); + errorLevelSelector.sendKeys(errorLevel.toString().toLowerCase()); + errorLevelSelector.sendKeys(getReturn()); + } + + private Keys getReturn() { + if (BrowserUtil.isPhantomJS(getDesiredCapabilities())) { + return Keys.ENTER; + } else { + return Keys.RETURN; + } + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java b/uitest/src/test/java/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java index 99c7a1d770..31011b8837 100644 --- a/uitest/src/test/java/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java +++ b/uitest/src/test/java/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java @@ -84,8 +84,8 @@ public class TabSheetErrorTooltipTest extends MultiBrowserTest { } private WebElement getCurrentErrorMessage() { - return getDriver() - .findElement(By.xpath("//div[@class='v-errormessage']")); + return getDriver().findElement( + By.xpath("//div[contains(@class, 'v-errormessage')]")); } private void assertTooltip(String tooltip) { |