From: Adam Wagner Date: Tue, 26 Sep 2017 07:20:49 +0000 (+0300) Subject: Implement error level on client side (#9816) X-Git-Tag: 7.7.11~3 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=de2c1ce5b7706c3ee355205265d2440667fb6b6f;p=vaadin-framework.git Implement error level on client side (#9816) Add additional class names and style to components and error indicators to distinguish different error levels. Vaadin 7 solution for #3139 --- diff --git a/client/src/main/java/com/vaadin/client/StyleConstants.java b/client/src/main/java/com/vaadin/client/StyleConstants.java index fe04fc7c46..61ee4327a4 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 6e3e063be2..b264f930ad 100644 --- a/client/src/main/java/com/vaadin/client/TooltipInfo.java +++ b/client/src/main/java/com/vaadin/client/TooltipInfo.java @@ -15,60 +15,164 @@ */ package com.vaadin.client; +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; 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) { setTitle(tooltip); } + /** + * Constructs a new tooltip info instance. + * + * @param tooltip + * tooltip title + * @param errorMessage + * error message + */ public TooltipInfo(String tooltip, String errorMessage) { this(tooltip, errorMessage, null); } + /** + * Constructs a new tooltip info instance. + * + * @param tooltip + * tooltip title + * @param errorMessage + * error message + * @param identifier + * the tooltip's identifier + */ public TooltipInfo(String tooltip, String errorMessage, Object identifier) { + this(tooltip, errorMessage, identifier, null); + } + + /** + * Constructs a new tooltip info instance. + * + * @param tooltip + * tooltip title + * @param errorMessage + * error message + * @param identifier + * the tooltip's identifier + * @param errorLevel + * error level + */ + public TooltipInfo(String tooltip, String errorMessage, Object identifier, + ErrorLevel errorLevel) { setIdentifier(identifier); setTitle(tooltip); 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 error level. + * + * @return the error level + */ + public ErrorLevel getErrorLevel() { + return errorLevel; + } + + /** + * Sets the error level. + * + * @param errorLevel + * the error level to set + */ + public void setErrorLevel(ErrorLevel errorLevel) { + this.errorLevel = errorLevel; + } + /** * Checks is a message has been defined for the tooltip. * @@ -80,9 +184,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 1d79bd57cc..7268e68e2a 100644 --- a/client/src/main/java/com/vaadin/client/VCaption.java +++ b/client/src/main/java/com/vaadin/client/VCaption.java @@ -25,6 +25,7 @@ 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.AbstractFieldConnector; import com.vaadin.client.ui.Icon; @@ -34,6 +35,7 @@ import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.AbstractFieldState; import com.vaadin.shared.ComponentConstants; import com.vaadin.shared.ui.ComponentStateUtil; +import com.vaadin.shared.ui.ErrorLevel; public class VCaption extends HTML { @@ -264,7 +266,7 @@ public class VCaption extends HTML { errorIndicatorElement = DOM.createDiv(); DOM.setInnerHTML(errorIndicatorElement, " "); DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); + StyleConstants.STYLE_NAME_ERROR_INDICATOR); DOM.insertChild(getElement(), errorIndicatorElement, getInsertPosition(InsertPosition.ERROR)); @@ -273,6 +275,11 @@ public class VCaption extends HTML { Roles.getTextboxRole().setAriaHiddenState(errorIndicatorElement, true); } + + ErrorUtil.setErrorLevelStyle(errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, + owner.getState().errorLevel); + } else if (errorIndicatorElement != null) { // Remove existing getElement().removeChild(errorIndicatorElement); @@ -323,6 +330,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 @@ -406,11 +421,15 @@ public class VCaption extends HTML { errorIndicatorElement = DOM.createDiv(); DOM.setInnerHTML(errorIndicatorElement, " "); DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); + StyleConstants.STYLE_NAME_ERROR_INDICATOR); DOM.insertChild(getElement(), errorIndicatorElement, getInsertPosition(InsertPosition.ERROR)); } + + ErrorUtil.setErrorLevelStyle(errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel); + } else if (errorIndicatorElement != null) { // Remove existing getElement().removeChild(errorIndicatorElement); diff --git a/client/src/main/java/com/vaadin/client/VErrorMessage.java b/client/src/main/java/com/vaadin/client/VErrorMessage.java index fa7fe1a51a..e13bca9c6a 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"; @@ -57,6 +59,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. * diff --git a/client/src/main/java/com/vaadin/client/VTooltip.java b/client/src/main/java/com/vaadin/client/VTooltip.java index 09d3ab5d65..64f36fda47 100644 --- a/client/src/main/java/com/vaadin/client/VTooltip.java +++ b/client/src/main/java/com/vaadin/client/VTooltip.java @@ -137,6 +137,7 @@ public class VTooltip extends VOverlay { && !info.getErrorMessage().isEmpty()) { em.setVisible(true); em.updateMessage(info.getErrorMessage()); + em.updateErrorLevel(info.getErrorLevel()); } else { em.setVisible(false); } @@ -440,6 +441,7 @@ public class VTooltip extends VOverlay { @Override public void hide() { em.updateMessage(""); + em.updateErrorLevel(null); description.setInnerHTML(""); 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 d6d36c1cb1..8ce2e0c500 100644 --- a/client/src/main/java/com/vaadin/client/WidgetUtil.java +++ b/client/src/main/java/com/vaadin/client/WidgetUtil.java @@ -45,6 +45,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; /** @@ -1822,4 +1823,35 @@ public class WidgetUtil { // 12 + int(30.6) / 60 = 12 + 30/60 = 12.5 return integerPart + ((int) nrFractions) / divisor; } + + /** + * Utility methods for displaying error message on components. + */ + 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); + } + } + } + } } 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 9e2854c259..0416375d6f 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.metadata.NoDataException; @@ -637,6 +638,10 @@ public abstract class AbstractComponentConnector extends AbstractConnector setWidgetStyleNameWithPrefix(primaryStyleName, StyleConstants.ERROR_EXT, null != state.errorMessage); + // add or remove error level style name + ErrorUtil.setErrorLevelStyle(getWidget().getElement(), + primaryStyleName + StyleConstants.ERROR_EXT, state.errorLevel); + // add additional user defined style names as class names, prefixed with // component default class name. remove nonexistent style names. @@ -764,7 +769,8 @@ public abstract class AbstractComponentConnector extends AbstractConnector @Override public TooltipInfo getTooltipInfo(Element element) { - return new TooltipInfo(getState().description, getState().errorMessage); + return new TooltipInfo(getState().description, getState().errorMessage, + null, getState().errorLevel); } @Override 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 0e202c3153..642669d10d 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/VFormLayout.java b/client/src/main/java/com/vaadin/client/ui/VFormLayout.java index a221222b92..9ee10cd99c 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); } } @@ -360,7 +362,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; @@ -373,7 +376,7 @@ public class VFormLayout extends SimplePanel { errorIndicatorElement = DOM.createDiv(); DOM.setInnerHTML(errorIndicatorElement, " "); DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); + StyleConstants.STYLE_NAME_ERROR_INDICATOR); DOM.appendChild(getElement(), errorIndicatorElement); // Hide the error indicator from screen reader, as this @@ -382,6 +385,9 @@ public class VFormLayout extends SimplePanel { .setAriaHiddenState(errorIndicatorElement, true); } + ErrorUtil.setErrorLevelStyle(errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel); + } else if (errorIndicatorElement != null) { DOM.removeChild(getElement(), 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 a48703c914..177d026fa1 100644 --- a/client/src/main/java/com/vaadin/client/ui/VPanel.java +++ b/client/src/main/java/com/vaadin/client/ui/VPanel.java @@ -24,8 +24,11 @@ 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.StyleConstants; +import com.vaadin.client.WidgetUtil.ErrorUtil; import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler; +import com.vaadin.shared.ui.ErrorLevel; public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner, Focusable { @@ -134,15 +137,20 @@ public class VPanel extends SimplePanel } /** For internal use only. May be removed or replaced in the future. */ - public void setErrorIndicatorVisible(boolean showError) { + public void setErrorIndicatorVisible(boolean showError, + ErrorLevel errorLevel) { if (showError) { if (errorIndicatorElement == null) { errorIndicatorElement = DOM.createSpan(); DOM.setElementProperty(errorIndicatorElement, "className", - "v-errorindicator"); + StyleConstants.STYLE_NAME_ERROR_INDICATOR); DOM.sinkEvents(errorIndicatorElement, Event.MOUSEEVENTS); sinkEvents(Event.MOUSEEVENTS); } + + ErrorUtil.setErrorLevelStyle(errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel); + DOM.insertBefore(captionNode, errorIndicatorElement, captionText); } else if (errorIndicatorElement != null) { DOM.removeChild(captionNode, errorIndicatorElement); 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 ca7db968d8..4a57a40f16 100644 --- a/client/src/main/java/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/main/java/com/vaadin/client/ui/VTabsheet.java @@ -339,7 +339,8 @@ public class VTabsheet extends VTabsheetBase if (tabState.description != null || tabState.componentError != null) { setTooltipInfo(new TooltipInfo(tabState.description, - tabState.componentError, this)); + tabState.componentError, this, + tabState.componentErrorLevel)); } else { setTooltipInfo(null); } @@ -351,6 +352,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 0bd403edff..34e72b2fb5 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,14 +52,19 @@ public class ButtonConnector extends AbstractComponentConnector ConnectorFocusAndBlurHandler.addHandlers(this); } - @OnStateChange("errorMessage") - void setErrorMessage() { + @OnStateChange({"errorMessage", "errorLevel"}) + void setErrorMessageAndLevel() { if (null != getState().errorMessage) { if (getWidget().errorIndicatorElement == null) { getWidget().errorIndicatorElement = DOM.createSpan(); - getWidget().errorIndicatorElement - .setClassName("v-errorindicator"); + getWidget().errorIndicatorElement.setClassName( + StyleConstants.STYLE_NAME_ERROR_INDICATOR); } + + ErrorUtil.setErrorLevelStyle(getWidget().errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, + getState().errorLevel); + getWidget().wrapper.insertFirst(getWidget().errorIndicatorElement); } else if (getWidget().errorIndicatorElement != 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 2e58124494..0c877406c2 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; @@ -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/client/src/main/java/com/vaadin/client/ui/form/FormConnector.java b/client/src/main/java/com/vaadin/client/ui/form/FormConnector.java index 3c5da2bbd8..0203987d31 100644 --- a/client/src/main/java/com/vaadin/client/ui/form/FormConnector.java +++ b/client/src/main/java/com/vaadin/client/ui/form/FormConnector.java @@ -125,6 +125,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/client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java b/client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java index 682d0dfd1f..da1fd90477 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 @@ -255,7 +255,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 fb49db05c9..03ddbd067c 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; @@ -75,8 +77,13 @@ public class LinkConnector extends AbstractComponentConnector { if (getWidget().errorIndicatorElement == null) { getWidget().errorIndicatorElement = DOM.createDiv(); DOM.setElementProperty(getWidget().errorIndicatorElement, - "className", "v-errorindicator"); + "className", StyleConstants.STYLE_NAME_ERROR_INDICATOR); } + + ErrorUtil.setErrorLevelStyle(getWidget().errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, + getState().errorLevel); + DOM.insertChild(getWidget().getElement(), getWidget().errorIndicatorElement, 0); } else if (getWidget().errorIndicatorElement != 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 81823c3d3c..8a9f53cfc4 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; @@ -59,9 +61,14 @@ public class NativeButtonConnector extends AbstractComponentConnector { if (null != getState().errorMessage) { if (getWidget().errorIndicatorElement == null) { getWidget().errorIndicatorElement = DOM.createSpan(); - getWidget().errorIndicatorElement - .setClassName("v-errorindicator"); + getWidget().errorIndicatorElement.setClassName( + StyleConstants.STYLE_NAME_ERROR_INDICATOR); } + + ErrorUtil.setErrorLevelStyle(getWidget().errorIndicatorElement, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, + getState().errorLevel); + getWidget().getElement().insertBefore( getWidget().errorIndicatorElement, getWidget().captionElement); 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 960bf71884..6fe2b4af18 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 @@ -276,8 +276,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 2315f0bc4b..e7654091da 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 @@ -31,12 +31,14 @@ import com.vaadin.client.BrowserInfo; 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.Icon; import com.vaadin.client.ui.ImageIcon; import com.vaadin.client.ui.layout.ElementResizeEvent; 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. @@ -519,6 +521,36 @@ public class Slot extends SimplePanel { public void setCaption(String captionText, Icon icon, List 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 + */ + public void setCaption(String captionText, Icon icon, List 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 @@ -611,8 +643,13 @@ public class Slot extends SimplePanel { if (error != null && showError) { if (errorIcon == null) { errorIcon = DOM.createSpan(); - errorIcon.setClassName("v-errorindicator"); + errorIcon.setClassName( + StyleConstants.STYLE_NAME_ERROR_INDICATOR); } + + ErrorUtil.setErrorLevelStyle(errorIcon, + StyleConstants.STYLE_NAME_ERROR_INDICATOR, errorLevel); + caption.appendChild(errorIcon); } else if (errorIcon != null) { errorIcon.removeFromParent(); 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 9cf90b6254..8e6358b156 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,7 +143,8 @@ public class PanelConnector extends AbstractSingleComponentContainerConnector getWidget().setIconUri(null, client); } - getWidget().setErrorIndicatorVisible(null != getState().errorMessage); + getWidget().setErrorIndicatorVisible(null != getState().errorMessage, + getState().errorLevel); // We may have actions attached to this panel if (uidl.getChildCount() > 0) { diff --git a/server/src/main/java/com/vaadin/server/ErrorMessage.java b/server/src/main/java/com/vaadin/server/ErrorMessage.java index 48ce3a78df..6107d5ab5b 100644 --- a/server/src/main/java/com/vaadin/server/ErrorMessage.java +++ b/server/src/main/java/com/vaadin/server/ErrorMessage.java @@ -80,6 +80,26 @@ public interface ErrorMessage extends Serializable { return text; } + /** + * Converts this to an error level that can be used on the client side. + * + * @return error level for the client side + */ + public com.vaadin.shared.ui.ErrorLevel convertToShared() { + switch (this) { + case INFORMATION: + return com.vaadin.shared.ui.ErrorLevel.INFO; + case WARNING: + return com.vaadin.shared.ui.ErrorLevel.WARNING; + case CRITICAL: + return com.vaadin.shared.ui.ErrorLevel.CRITICAL; + case SYSTEMERROR: + return com.vaadin.shared.ui.ErrorLevel.SYSTEM; + case ERROR: + default: + return com.vaadin.shared.ui.ErrorLevel.ERROR; + } + } } /** diff --git a/server/src/main/java/com/vaadin/ui/AbstractComponent.java b/server/src/main/java/com/vaadin/ui/AbstractComponent.java index 24bb9f8f79..4da06d3848 100644 --- a/server/src/main/java/com/vaadin/ui/AbstractComponent.java +++ b/server/src/main/java/com/vaadin/ui/AbstractComponent.java @@ -782,8 +782,10 @@ public abstract class AbstractComponent extends AbstractClientConnector ErrorMessage error = getErrorMessage(); if (null != error) { getState().errorMessage = error.getFormattedHtmlMessage(); + getState().errorLevel = error.getErrorLevel().convertToShared(); } else { getState().errorMessage = null; + getState().errorLevel = null; } getState().immediate = isImmediate(); diff --git a/server/src/main/java/com/vaadin/ui/TabSheet.java b/server/src/main/java/com/vaadin/ui/TabSheet.java index ce9214ae40..27b2cfb395 100644 --- a/server/src/main/java/com/vaadin/ui/TabSheet.java +++ b/server/src/main/java/com/vaadin/ui/TabSheet.java @@ -1264,9 +1264,16 @@ 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() + .convertToShared(); + } else { + tabState.componentError = null; + tabState.componentErrorLevel = null; + } + markAsDirty(); } diff --git a/shared/src/main/java/com/vaadin/shared/AbstractComponentState.java b/shared/src/main/java/com/vaadin/shared/AbstractComponentState.java index 755615c00b..8bbcc3eb15 100644 --- a/shared/src/main/java/com/vaadin/shared/AbstractComponentState.java +++ b/shared/src/main/java/com/vaadin/shared/AbstractComponentState.java @@ -20,6 +20,7 @@ import java.util.List; import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.communication.SharedState; +import com.vaadin.shared.ui.ErrorLevel; /** * Default shared state implementation for AbstractComponent. @@ -43,9 +44,11 @@ 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 */ + 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..2993bef43f --- /dev/null +++ b/shared/src/main/java/com/vaadin/shared/ui/ErrorLevel.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 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 +} 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 243dd92afb..c9e18508f7 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 @@ -17,6 +17,8 @@ package com.vaadin.shared.ui.tabsheet; import java.io.Serializable; +import com.vaadin.shared.ui.ErrorLevel; + /** * Shared state of a single tab in a Tabsheet or an Accordion. * @@ -33,6 +35,7 @@ public class TabState implements Serializable { public String styleName; public String key; public String componentError; + public ErrorLevel componentErrorLevel; public String id; public String iconAltText; 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 e9056ef17a..32b2aec3bc 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/components/_combobox.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/components/_combobox.scss @@ -31,6 +31,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 6ff8a70dba..f5cb8154e8 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 50cb7b8042..1b3552763d 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 { @@ -326,13 +345,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 55de987120..c36864e699 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss @@ -339,6 +339,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; @@ -400,8 +420,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 3c9c914499..b8ab053513 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/shared/_tooltip.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/shared/_tooltip.scss @@ -62,6 +62,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. * @@ -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 4634a71fea..8f1aaa257b 100644 --- a/themes/src/main/themes/VAADIN/themes/valo/shared/_variables.scss +++ b/themes/src/main/themes/VAADIN/themes/valo/shared/_variables.scss @@ -206,6 +206,46 @@ $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. @@ -213,7 +253,7 @@ $v-selection-color: $v-focus-color !default; * @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..f4a25bde5a --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/components/ErrorLevels.java @@ -0,0 +1,172 @@ +package com.vaadin.tests.components; + +import java.util.Arrays; + +import com.vaadin.annotations.Theme; +import com.vaadin.data.Property; +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.tests.components.AbstractTestUI; +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 errorLevels; + private Button button; + private Button borderlessButton; + private Link link; + private ComboBox 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; + + @Override + protected void setup(VaadinRequest request) { + + errorLevels = new ComboBox("Error level", + Arrays.asList(ErrorMessage.ErrorLevel.values())); + errorLevels.setNullSelectionAllowed(false); + errorLevels.setValue(ErrorMessage.ErrorLevel.ERROR); + errorLevels.addValueChangeListener(new Property.ValueChangeListener() { + @Override + public void valueChange(Property.ValueChangeEvent 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); + + 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")); + } + + private ErrorMessage createErrorMessage(String text) { + return new UserError(text, AbstractErrorMessage.ContentMode.TEXT, + (ErrorMessage.ErrorLevel) errorLevels.getValue()); + } +} 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..adf0b1af43 --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/components/ErrorLevelsTest.java @@ -0,0 +1,161 @@ +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.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; +import com.vaadin.tests.tb3.newelements.ComboBoxElement; + +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 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 classNames = new ArrayList( + 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 getErrorLevelClassNames(String prefix, + Collection errorLevels) { + List classNames = new ArrayList(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 2e15c5bfaa..89e06b3b28 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) {