Просмотр исходного кода

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
tags/8.2.0.alpha2
Adam Wagner 6 лет назад
Родитель
Сommit
697f770287
55 измененных файлов: 1409 добавлений и 256 удалений
  1. 2
    0
      all/src/main/templates/release-notes.html
  2. 5
    0
      client/src/main/java/com/vaadin/client/StyleConstants.java
  3. 170
    4
      client/src/main/java/com/vaadin/client/TooltipInfo.java
  4. 45
    29
      client/src/main/java/com/vaadin/client/VCaption.java
  5. 14
    0
      client/src/main/java/com/vaadin/client/VErrorMessage.java
  6. 2
    0
      client/src/main/java/com/vaadin/client/VTooltip.java
  7. 54
    9
      client/src/main/java/com/vaadin/client/WidgetUtil.java
  8. 24
    1
      client/src/main/java/com/vaadin/client/ui/AbstractComponentConnector.java
  9. 42
    0
      client/src/main/java/com/vaadin/client/ui/HasErrorIndicatorElement.java
  10. 3
    1
      client/src/main/java/com/vaadin/client/ui/VAccordion.java
  11. 21
    2
      client/src/main/java/com/vaadin/client/ui/VButton.java
  12. 24
    2
      client/src/main/java/com/vaadin/client/ui/VCheckBox.java
  13. 33
    17
      client/src/main/java/com/vaadin/client/ui/VFormLayout.java
  14. 21
    2
      client/src/main/java/com/vaadin/client/ui/VLink.java
  15. 22
    2
      client/src/main/java/com/vaadin/client/ui/VNativeButton.java
  16. 23
    19
      client/src/main/java/com/vaadin/client/ui/VPanel.java
  17. 3
    1
      client/src/main/java/com/vaadin/client/ui/VTabsheet.java
  18. 2
    16
      client/src/main/java/com/vaadin/client/ui/button/ButtonConnector.java
  19. 3
    21
      client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
  20. 2
    1
      client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java
  21. 2
    14
      client/src/main/java/com/vaadin/client/ui/link/LinkConnector.java
  22. 2
    17
      client/src/main/java/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java
  23. 3
    2
      client/src/main/java/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
  24. 58
    9
      client/src/main/java/com/vaadin/client/ui/orderedlayout/Slot.java
  25. 0
    2
      client/src/main/java/com/vaadin/client/ui/panel/PanelConnector.java
  26. 8
    1
      compatibility-client/src/main/java/com/vaadin/v7/client/ui/checkbox/CheckBoxConnector.java
  27. 1
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/ui/form/FormConnector.java
  28. 1
    1
      compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java
  29. 1
    1
      compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java
  30. 1
    0
      compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java
  31. 1
    1
      compatibility-server/src/test/java/com/vaadin/v7/ui/AbstractLegacyComponentDeclarativeTest.java
  32. 2
    0
      server/src/main/java/com/vaadin/server/AbstractErrorMessage.java
  33. 4
    2
      server/src/main/java/com/vaadin/server/CompositeErrorMessage.java
  34. 6
    59
      server/src/main/java/com/vaadin/server/ErrorMessage.java
  35. 3
    1
      server/src/main/java/com/vaadin/server/SystemError.java
  36. 2
    0
      server/src/main/java/com/vaadin/server/UserError.java
  37. 3
    1
      server/src/main/java/com/vaadin/ui/AbstractComponent.java
  38. 9
    3
      server/src/main/java/com/vaadin/ui/TabSheet.java
  39. 1
    1
      server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTest.java
  40. 1
    1
      server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTestBase.java
  41. 10
    3
      shared/src/main/java/com/vaadin/shared/AbstractComponentState.java
  42. 58
    0
      shared/src/main/java/com/vaadin/shared/ui/ErrorLevel.java
  43. 9
    0
      shared/src/main/java/com/vaadin/shared/ui/tabsheet/TabState.java
  44. 1
    1
      tests/screenshots
  45. 55
    0
      themes/src/main/themes/VAADIN/themes/valo/components/_combobox.scss
  46. 55
    0
      themes/src/main/themes/VAADIN/themes/valo/components/_datefield.scss
  47. 67
    3
      themes/src/main/themes/VAADIN/themes/valo/components/_textfield.scss
  48. 34
    0
      themes/src/main/themes/VAADIN/themes/valo/components/_twincolselect.scss
  49. 22
    2
      themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss
  50. 60
    0
      themes/src/main/themes/VAADIN/themes/valo/shared/_tooltip.scss
  51. 41
    1
      themes/src/main/themes/VAADIN/themes/valo/shared/_variables.scss
  52. 210
    0
      uitest/src/main/java/com/vaadin/tests/components/ErrorLevels.java
  53. 1
    1
      uitest/src/main/java/com/vaadin/tests/themes/valo/CommonParts.java
  54. 160
    0
      uitest/src/test/java/com/vaadin/tests/components/ErrorLevelsTest.java
  55. 2
    2
      uitest/src/test/java/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java

+ 2
- 0
all/src/main/templates/release-notes.html Просмотреть файл

<li><tt>DataCommunicator</tt> method <tt>getDataProviderSize</tt> is now <tt>public</tt>, not <tt>protected</tt>.</li> <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>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>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>&lt;span class="v-errorindicator"&gt;&lt;/span&gt;</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> <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>

+ 5
- 0
client/src/main/java/com/vaadin/client/StyleConstants.java Просмотреть файл

public static final String REQUIRED_EXT = "-required"; public static final String REQUIRED_EXT = "-required";


public static final String ERROR_EXT = "-error"; 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";
} }

+ 170
- 4
client/src/main/java/com/vaadin/client/TooltipInfo.java Просмотреть файл

package com.vaadin.client; package com.vaadin.client;


import com.vaadin.shared.ui.ContentMode; import com.vaadin.shared.ui.ContentMode;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.shared.util.SharedUtil; 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 { public class TooltipInfo {


private String title; private String title;


private String errorMessageHtml; private String errorMessageHtml;


private ErrorLevel errorLevel;

// Contains the tooltip's identifier. If a tooltip's contents and this // Contains the tooltip's identifier. If a tooltip's contents and this
// identifier haven't changed, the tooltip won't be updated in subsequent // identifier haven't changed, the tooltip won't be updated in subsequent
// events. // events.
private Object identifier; private Object identifier;


/**
* Constructs a new tooltip info instance.
*/
public TooltipInfo() { public TooltipInfo() {
} }


/**
* Constructs a new tooltip info instance.
*
* @param tooltip
* tooltip title
*/
public TooltipInfo(String tooltip) { public TooltipInfo(String tooltip) {
this(tooltip, ContentMode.PREFORMATTED); this(tooltip, ContentMode.PREFORMATTED);
} }
/** /**
* Constructs a new instance using the {@code tooltip} for the title and * Constructs a new instance using the {@code tooltip} for the title and
* {@code errorMessage} as a description. * {@code errorMessage} as a description.
*
*
* @param tooltip * @param tooltip
* tooltip title * tooltip title
* @param errorMessage * @param errorMessage
* error description * error description
*
*
* @deprecated use {@link #TooltipInfo(String, ContentMode, String)} instead * @deprecated use {@link #TooltipInfo(String, ContentMode, String)} instead
*/ */
@Deprecated @Deprecated
/** /**
* Constructs a new instance using the {@code tooltip} for the title, * Constructs a new instance using the {@code tooltip} for the title,
* {@code errorMessage} as a description and {@code identifier} as its id. * {@code errorMessage} as a description and {@code identifier} as its id.
*
*
* @param tooltip * @param tooltip
* tooltip title * tooltip title
* @param errorMessage * @param errorMessage
* error description * error description
* @param identifier * @param identifier
*
* the tooltip's identifier
*
* @deprecated use {@link #TooltipInfo(String, ContentMode, String, Object)} * @deprecated use {@link #TooltipInfo(String, ContentMode, String, Object)}
* instead * instead
*/ */
this(tooltip, ContentMode.HTML, errorMessage, identifier); 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) { public TooltipInfo(String tooltip, ContentMode mode) {
setTitle(tooltip); setTitle(tooltip);
setContentMode(mode); 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) { public TooltipInfo(String tooltip, ContentMode mode, String errorMessage) {
this(tooltip, mode, errorMessage, null); 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, public TooltipInfo(String tooltip, ContentMode mode, String errorMessage,
Object identifier) { 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); setIdentifier(identifier);
setTitle(tooltip); setTitle(tooltip);
setContentMode(mode); setContentMode(mode);
setErrorMessage(errorMessage); setErrorMessage(errorMessage);
setErrorLevel(errorLevel);
} }


/**
* Sets the tooltip's identifier.
*
* @param identifier
* the identifier to set
*/
public void setIdentifier(Object identifier) { public void setIdentifier(Object identifier) {
this.identifier = identifier; this.identifier = identifier;
} }


/**
* Gets the tooltip's identifier.
*
* @return the identifier
*/
public Object getIdentifier() { public Object getIdentifier() {
return identifier; return identifier;
} }


/**
* Gets the tooltip title.
*
* @return the title
*/
public String getTitle() { public String getTitle() {
return title; return title;
} }


/**
* Sets the tooltip title.
*
* @param title
* the title to set
*/
public void setTitle(String title) { public void setTitle(String title) {
this.title = title; this.title = title;
} }


/**
* Gets the error message.
*
* @return the error message
*/
public String getErrorMessage() { public String getErrorMessage() {
return errorMessageHtml; return errorMessageHtml;
} }


/**
* Sets the error message.
*
* @param errorMessage
* the error message to set
*/
public void setErrorMessage(String errorMessage) { public void setErrorMessage(String errorMessage) {
errorMessageHtml = errorMessage; errorMessageHtml = errorMessage;
} }


/**
* Gets the tooltip title's content mode.
*
* @return the content mode
*/
public ContentMode getContentMode() { public ContentMode getContentMode() {
return contentMode; return contentMode;
} }


/**
* Sets the tooltip title's content mode.
*
* @param contentMode
* the content mode to set
*/
public void setContentMode(ContentMode contentMode) { public void setContentMode(ContentMode contentMode) {
this.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. * Checks is a message has been defined for the tooltip.
* *
|| (errorMessageHtml != null && !errorMessageHtml.isEmpty()); || (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) { public boolean equals(TooltipInfo other) {
return (other != null && SharedUtil.equals(other.title, title) return (other != null && SharedUtil.equals(other.title, title)
&& SharedUtil.equals(other.errorMessageHtml, errorMessageHtml) && SharedUtil.equals(other.errorMessageHtml, errorMessageHtml)
&& SharedUtil.equals(other.errorLevel, errorLevel)
&& other.identifier == identifier); && other.identifier == identifier);
} }
} }

+ 45
- 29
client/src/main/java/com/vaadin/client/VCaption.java Просмотреть файл

import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHTML; import com.google.gwt.user.client.ui.HasHTML;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.HasErrorIndicator; import com.vaadin.client.ui.HasErrorIndicator;
import com.vaadin.client.ui.HasErrorIndicatorElement;
import com.vaadin.client.ui.HasRequiredIndicator; import com.vaadin.client.ui.HasRequiredIndicator;
import com.vaadin.client.ui.Icon; import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.ImageIcon; import com.vaadin.client.ui.ImageIcon;
import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.ComponentConstants; import com.vaadin.shared.ComponentConstants;
import com.vaadin.shared.ui.ComponentStateUtil; 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"; public static final String CLASSNAME = "v-caption";


AriaHelper.handleInputInvalid(owner.getWidget(), showError); AriaHelper.handleInputInvalid(owner.getWidget(), showError);


if (showError) { if (showError) {
if (errorIndicatorElement == null) {
errorIndicatorElement = DOM.createDiv();
DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
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); return (wasPlacedAfterComponent != placedAfterComponent);
public boolean updateCaptionWithoutOwner(String caption, boolean disabled, public boolean updateCaptionWithoutOwner(String caption, boolean disabled,
boolean hasDescription, boolean hasError, String iconURL, boolean hasDescription, boolean hasError, String iconURL,
String iconAltText) { 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; boolean wasPlacedAfterComponent = placedAfterComponent;


// Caption is placed after component unless there is some part which // Caption is placed after component unless there is some part which
} }


if (hasError) { if (hasError) {
if (errorIndicatorElement == null) {
errorIndicatorElement = DOM.createDiv();
DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
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); return (wasPlacedAfterComponent != placedAfterComponent);
private static Logger getLogger() { private static Logger getLogger() {
return Logger.getLogger(VCaption.class.getName()); 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;
}
}
} }

+ 14
- 0
client/src/main/java/com/vaadin/client/VErrorMessage.java Просмотреть файл

import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ui.VOverlay; import com.vaadin.client.ui.VOverlay;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.shared.ui.ErrorLevel;


public class VErrorMessage extends FlowPanel { public class VErrorMessage extends FlowPanel {
public static final String CLASSNAME = "v-errormessage"; public static final String CLASSNAME = "v-errormessage";
} }
} }


/**
* 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. * Shows this error message next to given element.
* *

+ 2
- 0
client/src/main/java/com/vaadin/client/VTooltip.java Просмотреть файл

&& !info.getErrorMessage().isEmpty()) { && !info.getErrorMessage().isEmpty()) {
em.setVisible(true); em.setVisible(true);
em.updateMessage(info.getErrorMessage()); em.updateMessage(info.getErrorMessage());
em.updateErrorLevel(info.getErrorLevel());
} else { } else {
em.setVisible(false); em.setVisible(false);
} }
@Override @Override
public void hide() { public void hide() {
em.updateMessage(""); em.updateMessage("");
em.updateErrorLevel(null);
description.setHTML(""); description.setHTML("");


updatePosition(null, true); updatePosition(null, true);

+ 54
- 9
client/src/main/java/com/vaadin/client/WidgetUtil.java Просмотреть файл

import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.Widget;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.shared.util.SharedUtil; import com.vaadin.shared.util.SharedUtil;


/** /**
com.google.gwt.dom.client.Element el, String p) com.google.gwt.dom.client.Element el, String p)
/*-{ /*-{
try { try {
if (el.currentStyle) { if (el.currentStyle) {
// IE // IE
return el.currentStyle[p]; return el.currentStyle[p];
} catch (e) { } catch (e) {
return ""; return "";
} }
}-*/; }-*/;


/** /**
try { try {
el.focus(); el.focus();
} catch (e) { } catch (e) {
} }
}-*/; }-*/;


if ($wnd.document.activeElement) { if ($wnd.document.activeElement) {
return $wnd.document.activeElement; return $wnd.document.activeElement;
} }
return null; return null;
}-*/; }-*/;


/*-{ /*-{
var top = elem.offsetTop; var top = elem.offsetTop;
var height = elem.offsetHeight; var height = elem.offsetHeight;
if (elem.parentNode != elem.offsetParent) { if (elem.parentNode != elem.offsetParent) {
top -= elem.parentNode.offsetTop; top -= elem.parentNode.offsetTop;
} }
var cur = elem.parentNode; var cur = elem.parentNode;
while (cur && (cur.nodeType == 1)) { while (cur && (cur.nodeType == 1)) {
if (top < cur.scrollTop) { if (top < cur.scrollTop) {
if (top + height > cur.scrollTop + cur.clientHeight) { if (top + height > cur.scrollTop + cur.clientHeight) {
cur.scrollTop = (top + height) - cur.clientHeight; cur.scrollTop = (top + height) - cur.clientHeight;
} }
var offsetTop = cur.offsetTop; var offsetTop = cur.offsetTop;
if (cur.parentNode != cur.offsetParent) { if (cur.parentNode != cur.offsetParent) {
offsetTop -= cur.parentNode.offsetTop; offsetTop -= cur.parentNode.offsetTop;
} }
top += offsetTop - cur.scrollTop; top += offsetTop - cur.scrollTop;
cur = cur.parentNode; cur = cur.parentNode;
} }
} }
var heightWithoutBorder = cloneElement.offsetHeight; var heightWithoutBorder = cloneElement.offsetHeight;
parentElement.removeChild(cloneElement); parentElement.removeChild(cloneElement);
return heightWithBorder - heightWithoutBorder; return heightWithBorder - heightWithoutBorder;
} }
}-*/; }-*/;
int relativeTop = element.getAbsoluteTop() - Window.getScrollTop(); int relativeTop = element.getAbsoluteTop() - Window.getScrollTop();
return WidgetUtil.getTouchOrMouseClientY(event) - relativeTop; 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;
}
}
} }

+ 24
- 1
client/src/main/java/com/vaadin/client/ui/AbstractComponentConnector.java Просмотреть файл

import com.vaadin.client.Util; import com.vaadin.client.Util;
import com.vaadin.client.VConsole; import com.vaadin.client.VConsole;
import com.vaadin.client.WidgetUtil; import com.vaadin.client.WidgetUtil;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.extensions.DragSourceExtensionConnector; import com.vaadin.client.extensions.DragSourceExtensionConnector;
Profiler.leave("AbstractComponentConnector.onStateChanged"); 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 @Override
public void setWidgetEnabled(boolean widgetEnabled) { public void setWidgetEnabled(boolean widgetEnabled) {
// add or remove v-disabled style name from the widget // add or remove v-disabled style name from the widget
@Override @Override
public TooltipInfo getTooltipInfo(Element element) { public TooltipInfo getTooltipInfo(Element element) {
return new TooltipInfo(getState().description, return new TooltipInfo(getState().description,
getState().descriptionContentMode, getState().errorMessage);
getState().descriptionContentMode, getState().errorMessage,
null, getState().errorLevel);
} }


@Override @Override

+ 42
- 0
client/src/main/java/com/vaadin/client/ui/HasErrorIndicatorElement.java Просмотреть файл

/*
* 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);
}

+ 3
- 1
client/src/main/java/com/vaadin/client/ui/VAccordion.java Просмотреть файл

caption.updateCaptionWithoutOwner(tabState.caption, caption.updateCaptionWithoutOwner(tabState.caption,
!tabState.enabled, hasAttribute(tabState.description), !tabState.enabled, hasAttribute(tabState.description),
hasAttribute(tabState.componentError), hasAttribute(tabState.componentError),
tabState.componentErrorLevel,
connector.getResourceUrl( connector.getResourceUrl(
ComponentConstants.ICON_RESOURCE + tabState.key));
ComponentConstants.ICON_RESOURCE + tabState.key),
tabState.iconAltText);
} }


private boolean hasAttribute(String string) { private boolean hasAttribute(String string) {

+ 21
- 2
client/src/main/java/com/vaadin/client/ui/VButton.java Просмотреть файл

import com.vaadin.client.BrowserInfo; import com.vaadin.client.BrowserInfo;
import com.vaadin.client.Util; import com.vaadin.client.Util;
import com.vaadin.client.WidgetUtil; 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"; public static final String CLASSNAME = "v-button";
private static final String CLASSNAME_PRESSED = "v-pressed"; private static final String CLASSNAME_PRESSED = "v-pressed";
public final Element wrapper = DOM.createSpan(); public final Element wrapper = DOM.createSpan();


/** For internal use only. May be removed or replaced in the future. */ /** 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. */ /** For internal use only. May be removed or replaced in the future. */
public final Element captionElement = DOM.createSpan(); public final Element captionElement = DOM.createSpan();
return ret; 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;
}
}
} }

+ 24
- 2
client/src/main/java/com/vaadin/client/ui/VCheckBox.java Просмотреть файл

import com.vaadin.client.BrowserInfo; import com.vaadin.client.BrowserInfo;
import com.vaadin.client.Util; import com.vaadin.client.Util;
import com.vaadin.client.VTooltip; import com.vaadin.client.VTooltip;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.ui.aria.AriaHelper; import com.vaadin.client.ui.aria.AriaHelper;
import com.vaadin.client.ui.aria.HandlesAriaInvalid; import com.vaadin.client.ui.aria.HandlesAriaInvalid;
import com.vaadin.client.ui.aria.HandlesAriaRequired; import com.vaadin.client.ui.aria.HandlesAriaRequired;


public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox 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"; public static final String CLASSNAME = "v-checkbox";


public ApplicationConnection client; public ApplicationConnection client;


/** For internal use only. May be removed or replaced in the future. */ /** 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. */ /** For internal use only. May be removed or replaced in the future. */
public Icon icon; public Icon icon;
public void setAriaInvalid(boolean invalid) { public void setAriaInvalid(boolean invalid) {
AriaHelper.handleInputInvalid(getCheckBoxElement(), 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;
}
}
} }

+ 33
- 17
client/src/main/java/com/vaadin/client/ui/VFormLayout.java Просмотреть файл

import com.vaadin.client.Focusable; import com.vaadin.client.Focusable;
import com.vaadin.client.StyleConstants; import com.vaadin.client.StyleConstants;
import com.vaadin.client.VTooltip; import com.vaadin.client.VTooltip;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.ui.aria.AriaHelper; import com.vaadin.client.ui.aria.AriaHelper;
import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.ComponentConstants; import com.vaadin.shared.ComponentConstants;
import com.vaadin.shared.ui.ComponentStateUtil; import com.vaadin.shared.ui.ComponentStateUtil;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.shared.ui.MarginInfo; import com.vaadin.shared.ui.MarginInfo;


/** /**
} }


public void updateError(Widget widget, String errorMessage, public void updateError(Widget widget, String errorMessage,
boolean hideErrors) {
ErrorLevel errorLevel, boolean hideErrors) {
final ErrorFlag e = widgetToError.get(widget); final ErrorFlag e = widgetToError.get(widget);
if (e != null) { if (e != null) {
e.updateError(errorMessage, hideErrors);
e.updateError(errorMessage, errorLevel, hideErrors);
} }


} }
} }


/** For internal use only. May be removed or replaced in the future. */ /** 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 private static final String CLASSNAME = VFormLayout.CLASSNAME
+ "-error-indicator"; + "-error-indicator";
Element errorIndicatorElement; Element errorIndicatorElement;
return owner; return owner;
} }


public void updateError(String errorMessage, boolean hideErrors) {
public void updateError(String errorMessage, ErrorLevel errorLevel,
boolean hideErrors) {
boolean showError = null != errorMessage; boolean showError = null != errorMessage;
if (hideErrors) { if (hideErrors) {
showError = false; showError = false;
AriaHelper.handleInputInvalid(owner.getWidget(), showError); AriaHelper.handleInputInvalid(owner.getWidget(), showError);


if (showError) { if (showError) {
if (errorIndicatorElement == null) {
errorIndicatorElement = DOM.createDiv();
DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
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) { } else if (errorIndicatorElement != null) {
DOM.removeChild(getElement(), errorIndicatorElement);
getElement().removeChild(errorIndicatorElement);
errorIndicatorElement = null; errorIndicatorElement = null;
} }
} }

} }
} }

+ 21
- 2
client/src/main/java/com/vaadin/client/ui/VLink.java Просмотреть файл

import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasEnabled; import com.google.gwt.user.client.ui.HasEnabled;
import com.vaadin.client.Util; import com.vaadin.client.Util;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.shared.ui.BorderStyle; 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"; public static final String CLASSNAME = "v-link";


public int targetHeight; public int targetHeight;


/** For internal use only. May be removed or replaced in the future. */ /** 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. */ /** For internal use only. May be removed or replaced in the future. */
public final Element anchor = DOM.createAnchor(); public final Element anchor = DOM.createAnchor();
this.enabled = enabled; 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;
}
}
} }

+ 22
- 2
client/src/main/java/com/vaadin/client/ui/VNativeButton.java Просмотреть файл

import com.vaadin.client.MouseEventDetailsBuilder; import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.StyleConstants; import com.vaadin.client.StyleConstants;
import com.vaadin.client.Util; import com.vaadin.client.Util;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.button.ButtonServerRpc; 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"; public static final String CLASSNAME = "v-nativebutton";


public ButtonServerRpc buttonRpcProxy; public ButtonServerRpc buttonRpcProxy;


/** For internal use only. May be removed or replaced in the future. */ /** 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. */ /** For internal use only. May be removed or replaced in the future. */
public final Element captionElement = DOM.createSpan(); public final Element captionElement = DOM.createSpan();
clickPending = false; 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;
}
}
} }

+ 23
- 19
client/src/main/java/com/vaadin/client/ui/VPanel.java Просмотреть файл

import com.google.gwt.user.client.ui.SimplePanel; import com.google.gwt.user.client.ui.SimplePanel;
import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Focusable; import com.vaadin.client.Focusable;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler; 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"; public static final String CLASSNAME = "v-panel";


DOM.setInnerHTML(captionText, text); DOM.setInnerHTML(captionText, text);
} }


/** 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. */ /** For internal use only. May be removed or replaced in the future. */
public void setIconUri(String iconUri, ApplicationConnection client) { public void setIconUri(String iconUri, ApplicationConnection client) {
if (icon != null) { if (icon != null) {
} }
touchScrollHandler.addElement(contentNode); 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;
}
}
} }

+ 3
- 1
client/src/main/java/com/vaadin/client/ui/VTabsheet.java Просмотреть файл

|| tabState.componentError != null) { || tabState.componentError != null) {
setTooltipInfo(new TooltipInfo(tabState.description, setTooltipInfo(new TooltipInfo(tabState.description,
tabState.descriptionContentMode, tabState.descriptionContentMode,
tabState.componentError, this));
tabState.componentError, this,
tabState.componentErrorLevel));
} else { } else {
setTooltipInfo(null); setTooltipInfo(null);
} }
boolean ret = updateCaptionWithoutOwner(captionString, boolean ret = updateCaptionWithoutOwner(captionString,
!tabState.enabled, hasAttribute(tabState.description), !tabState.enabled, hasAttribute(tabState.description),
hasAttribute(tabState.componentError), hasAttribute(tabState.componentError),
tabState.componentErrorLevel,
tab.getTabsheet().connector.getResourceUrl( tab.getTabsheet().connector.getResourceUrl(
ComponentConstants.ICON_RESOURCE + tabState.key), ComponentConstants.ICON_RESOURCE + tabState.key),
tabState.iconAltText); tabState.iconAltText);

+ 2
- 16
client/src/main/java/com/vaadin/client/ui/button/ButtonConnector.java Просмотреть файл

import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DOM;
import com.vaadin.client.MouseEventDetailsBuilder; import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.StyleConstants;
import com.vaadin.client.VCaption; import com.vaadin.client.VCaption;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
ConnectorFocusAndBlurHandler.addHandlers(this); 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") @OnStateChange("resources")
void onResourceChange() { void onResourceChange() {
if (getWidget().icon != null) { if (getWidget().icon != null) {

+ 3
- 21
client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java Просмотреть файл

import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event;
import com.vaadin.client.MouseEventDetailsBuilder; import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.StyleConstants;
import com.vaadin.client.VCaption; import com.vaadin.client.VCaption;
import com.vaadin.client.VTooltip; import com.vaadin.client.VTooltip;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.AbstractFieldConnector;
public void onStateChanged(StateChangeEvent stateChangeEvent) { public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent); super.onStateChanged(stateChangeEvent);


if (null != getState().errorMessage) {
getWidget().setAriaInvalid(true);

if (getWidget().errorIndicatorElement == null) {
getWidget().errorIndicatorElement = DOM.createSpan();
getWidget().errorIndicatorElement.setInnerHTML("&nbsp;");
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()); getWidget().setAriaRequired(isRequiredIndicatorVisible());
if (isReadOnly()) { if (isReadOnly()) {

+ 2
- 1
client/src/main/java/com/vaadin/client/ui/formlayout/FormLayoutConnector.java Просмотреть файл

} }


getWidget().table.updateError(component.getWidget(), getWidget().table.updateError(component.getWidget(),
component.getState().errorMessage, hideErrors);
component.getState().errorMessage,
component.getState().errorLevel, hideErrors);
} }


@Override @Override

+ 2
- 14
client/src/main/java/com/vaadin/client/ui/link/LinkConnector.java Просмотреть файл



import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DOM;
import com.vaadin.client.StyleConstants;
import com.vaadin.client.VCaption; import com.vaadin.client.VCaption;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.Icon; import com.vaadin.client.ui.Icon;
// Set link caption // Set link caption
VCaption.setCaptionText(getWidget().captionElement, getState()); 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) { if (getWidget().icon != null) {
getWidget().anchor.removeChild(getWidget().icon.getElement()); getWidget().anchor.removeChild(getWidget().icon.getElement());
getWidget().icon = null; getWidget().icon = null;

+ 2
- 17
client/src/main/java/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java Просмотреть файл

package com.vaadin.client.ui.nativebutton; package com.vaadin.client.ui.nativebutton;


import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DOM;
import com.vaadin.client.StyleConstants;
import com.vaadin.client.VCaption; import com.vaadin.client.VCaption;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
// Set text // Set text
VCaption.setCaptionText(getWidget(), getState()); 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) { if (getWidget().icon != null) {
getWidget().getElement().removeChild(getWidget().icon.getElement()); getWidget().getElement().removeChild(getWidget().icon.getElement());
getWidget().icon = null; getWidget().icon = null;

+ 3
- 2
client/src/main/java/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java Просмотреть файл

slot.setCaptionResizeListener(null); 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.handleInputRequired(child.getWidget(), required);
AriaHelper.handleInputInvalid(child.getWidget(), showError); AriaHelper.handleInputInvalid(child.getWidget(), showError);

+ 58
- 9
client/src/main/java/com/vaadin/client/ui/orderedlayout/Slot.java Просмотреть файл

import com.vaadin.client.LayoutManager; import com.vaadin.client.LayoutManager;
import com.vaadin.client.StyleConstants; import com.vaadin.client.StyleConstants;
import com.vaadin.client.WidgetUtil; import com.vaadin.client.WidgetUtil;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.ui.FontIcon; import com.vaadin.client.ui.FontIcon;
import com.vaadin.client.ui.HasErrorIndicatorElement;
import com.vaadin.client.ui.Icon; import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.ImageIcon; import com.vaadin.client.ui.ImageIcon;
import com.vaadin.client.ui.layout.ElementResizeListener; import com.vaadin.client.ui.layout.ElementResizeListener;
import com.vaadin.shared.ui.AlignmentInfo; import com.vaadin.shared.ui.AlignmentInfo;
import com.vaadin.shared.ui.ErrorLevel;


/** /**
* Represents a slot which contains the actual widget in the layout. * 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-"; private static final String ALIGN_CLASS_PREFIX = "v-align-";


public void setCaption(String captionText, Icon icon, List<String> styles, public void setCaption(String captionText, Icon icon, List<String> styles,
String error, boolean showError, boolean required, boolean enabled, String error, boolean showError, boolean required, boolean enabled,
boolean captionAsHtml) { 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 // TODO place for optimization: check if any of these have changed
// since last time, and only run those changes // since last time, and only run those changes


// Error // Error
if (error != null && showError) { 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) { if (caption != null) {
return hasRelativeWidth(); 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;
}
}
} }

+ 0
- 2
client/src/main/java/com/vaadin/client/ui/panel/PanelConnector.java Просмотреть файл

getWidget().setIconUri(null, client); getWidget().setIconUri(null, client);
} }


getWidget().setErrorIndicatorVisible(isErrorIndicatorVisible());

// We may have actions attached to this panel // We may have actions attached to this panel
if (uidl.getChildCount() > 0) { if (uidl.getChildCount() > 0) {
final int cnt = uidl.getChildCount(); final int cnt = uidl.getChildCount();

+ 8
- 1
compatibility-client/src/main/java/com/vaadin/v7/client/ui/checkbox/CheckBoxConnector.java Просмотреть файл

import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event;
import com.vaadin.client.MouseEventDetailsBuilder; import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.StyleConstants;
import com.vaadin.client.VCaption; import com.vaadin.client.VCaption;
import com.vaadin.client.VTooltip; import com.vaadin.client.VTooltip;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
getWidget().errorIndicatorElement = DOM.createSpan(); getWidget().errorIndicatorElement = DOM.createSpan();
getWidget().errorIndicatorElement.setInnerHTML("&nbsp;"); getWidget().errorIndicatorElement.setInnerHTML("&nbsp;");
DOM.setElementProperty(getWidget().errorIndicatorElement, DOM.setElementProperty(getWidget().errorIndicatorElement,
"className", "v-errorindicator");
"className", StyleConstants.STYLE_NAME_ERROR_INDICATOR);
DOM.appendChild(getWidget().getElement(), DOM.appendChild(getWidget().getElement(),
getWidget().errorIndicatorElement); getWidget().errorIndicatorElement);
DOM.sinkEvents(getWidget().errorIndicatorElement, DOM.sinkEvents(getWidget().errorIndicatorElement,
} else { } else {
getWidget().errorIndicatorElement.getStyle().clearDisplay(); getWidget().errorIndicatorElement.getStyle().clearDisplay();
} }

ErrorUtil.setErrorLevelStyle(getWidget().errorIndicatorElement,
StyleConstants.STYLE_NAME_ERROR_INDICATOR,
getState().errorLevel);

} else if (getWidget().errorIndicatorElement != null) { } else if (getWidget().errorIndicatorElement != null) {
getWidget().errorIndicatorElement.getStyle() getWidget().errorIndicatorElement.getStyle()
.setDisplay(Display.NONE); .setDisplay(Display.NONE);

+ 1
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/ui/form/FormConnector.java Просмотреть файл



if (null != getState().errorMessage) { if (null != getState().errorMessage) {
getWidget().errorMessage.updateMessage(getState().errorMessage); getWidget().errorMessage.updateMessage(getState().errorMessage);
getWidget().errorMessage.updateErrorLevel(getState().errorLevel);
getWidget().errorMessage.setVisible(true); getWidget().errorMessage.setVisible(true);
} else { } else {
getWidget().errorMessage.setVisible(false); getWidget().errorMessage.setVisible(false);

+ 1
- 1
compatibility-server/src/main/java/com/vaadin/v7/data/Buffered.java Просмотреть файл

import com.vaadin.data.Binder; import com.vaadin.data.Binder;
import com.vaadin.server.AbstractErrorMessage; import com.vaadin.server.AbstractErrorMessage;
import com.vaadin.server.ErrorMessage; import com.vaadin.server.ErrorMessage;
import com.vaadin.server.ErrorMessage.ErrorLevel;
import com.vaadin.server.ErrorMessageProducer; import com.vaadin.server.ErrorMessageProducer;
import com.vaadin.server.UserError; import com.vaadin.server.UserError;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.v7.data.Validator.InvalidValueException; import com.vaadin.v7.data.Validator.InvalidValueException;


/** /**

+ 1
- 1
compatibility-server/src/main/java/com/vaadin/v7/data/Validator.java Просмотреть файл

import com.vaadin.server.AbstractErrorMessage; import com.vaadin.server.AbstractErrorMessage;
import com.vaadin.server.AbstractErrorMessage.ContentMode; import com.vaadin.server.AbstractErrorMessage.ContentMode;
import com.vaadin.server.ErrorMessage; import com.vaadin.server.ErrorMessage;
import com.vaadin.server.ErrorMessage.ErrorLevel;
import com.vaadin.server.ErrorMessageProducer; import com.vaadin.server.ErrorMessageProducer;
import com.vaadin.server.UserError; import com.vaadin.server.UserError;
import com.vaadin.server.VaadinServlet; import com.vaadin.server.VaadinServlet;
import com.vaadin.shared.ui.ErrorLevel;


/** /**
* Interface that implements a method for validating if an {@link Object} is * Interface that implements a method for validating if an {@link Object} is

+ 1
- 0
compatibility-server/src/main/java/com/vaadin/v7/ui/Grid.java Просмотреть файл

import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.Registration; import com.vaadin.shared.Registration;
import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.data.sort.SortDirection;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.shared.util.SharedUtil; import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Component; import com.vaadin.ui.Component;

+ 1
- 1
compatibility-server/src/test/java/com/vaadin/v7/ui/AbstractLegacyComponentDeclarativeTest.java Просмотреть файл

import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;


import com.vaadin.server.ErrorMessage.ErrorLevel;
import com.vaadin.server.ExternalResource; import com.vaadin.server.ExternalResource;
import com.vaadin.server.FileResource; import com.vaadin.server.FileResource;
import com.vaadin.server.Responsive; import com.vaadin.server.Responsive;
import com.vaadin.server.ThemeResource; import com.vaadin.server.ThemeResource;
import com.vaadin.server.UserError; import com.vaadin.server.UserError;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.tests.design.DeclarativeTestBase; import com.vaadin.tests.design.DeclarativeTestBase;
import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Label; import com.vaadin.ui.Label;

+ 2
- 0
server/src/main/java/com/vaadin/server/AbstractErrorMessage.java Просмотреть файл

import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;


import com.vaadin.shared.ui.ErrorLevel;

/** /**
* Base class for component error messages. * Base class for component error messages.
* *

+ 4
- 2
server/src/main/java/com/vaadin/server/CompositeErrorMessage.java Просмотреть файл

import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;


import com.vaadin.shared.ui.ErrorLevel;

/** /**
* Class for combining multiple error messages together. * Class for combining multiple error messages together.
* *
*/ */
public CompositeErrorMessage(ErrorMessage... errorMessages) { public CompositeErrorMessage(ErrorMessage... errorMessages) {
super(null); super(null);
setErrorLevel(ErrorLevel.INFORMATION);
setErrorLevel(ErrorLevel.INFO);


for (ErrorMessage errorMessage : errorMessages) { for (ErrorMessage errorMessage : errorMessages) {
addErrorMessage(errorMessage); addErrorMessage(errorMessage);
public CompositeErrorMessage( public CompositeErrorMessage(
Collection<? extends ErrorMessage> errorMessages) { Collection<? extends ErrorMessage> errorMessages) {
super(null); super(null);
setErrorLevel(ErrorLevel.INFORMATION);
setErrorLevel(ErrorLevel.INFO);


for (ErrorMessage errorMessage : errorMessages) { for (ErrorMessage errorMessage : errorMessages) {
addErrorMessage(errorMessage); addErrorMessage(errorMessage);

+ 6
- 59
server/src/main/java/com/vaadin/server/ErrorMessage.java Просмотреть файл



import java.io.Serializable; import java.io.Serializable;


import com.vaadin.shared.ui.ErrorLevel;

/** /**
* Interface for rendering error messages to terminal. All the visible errors * Interface for rendering error messages to terminal. All the visible errors
* shown to user must implement this interface. * shown to user must implement this interface.
*/ */
public interface ErrorMessage extends 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 @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     * @deprecated As of 7.0, use {@link ErrorLevel#CRITICAL} instead    
public static final ErrorLevel WARNING = ErrorLevel.WARNING; 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 @Deprecated
public static final ErrorLevel INFORMATION = ErrorLevel.INFORMATION;
public static final ErrorLevel INFORMATION = ErrorLevel.INFO;


/** /**
* Gets the errors level. * Gets the errors level.

+ 3
- 1
server/src/main/java/com/vaadin/server/SystemError.java Просмотреть файл



package com.vaadin.server; package com.vaadin.server;


import com.vaadin.shared.ui.ErrorLevel;

/** /**
* <code>SystemError</code> is an error message for a problem caused by error in * <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 * system, not the user application code. The system error can contain technical
*/ */
public SystemError(String message) { public SystemError(String message) {
super(message); super(message);
setErrorLevel(ErrorLevel.SYSTEMERROR);
setErrorLevel(ErrorLevel.SYSTEM);
setMode(ContentMode.HTML); setMode(ContentMode.HTML);
setMessage(getHtmlMessage()); setMessage(getHtmlMessage());
} }

+ 2
- 0
server/src/main/java/com/vaadin/server/UserError.java Просмотреть файл



package com.vaadin.server; package com.vaadin.server;


import com.vaadin.shared.ui.ErrorLevel;

/** /**
* <code>UserError</code> is a controlled error occurred in application. User * <code>UserError</code> is a controlled error occurred in application. User
* errors are occur in normal usage of the application and guide the user. * errors are occur in normal usage of the application and guide the user.

+ 3
- 1
server/src/main/java/com/vaadin/ui/AbstractComponent.java Просмотреть файл

import com.vaadin.server.ClientConnector; import com.vaadin.server.ClientConnector;
import com.vaadin.server.ComponentSizeValidator; import com.vaadin.server.ComponentSizeValidator;
import com.vaadin.server.ErrorMessage; import com.vaadin.server.ErrorMessage;
import com.vaadin.server.ErrorMessage.ErrorLevel;
import com.vaadin.server.Extension; import com.vaadin.server.Extension;
import com.vaadin.server.Resource; import com.vaadin.server.Resource;
import com.vaadin.server.Responsive; import com.vaadin.server.Responsive;
import com.vaadin.shared.Registration; import com.vaadin.shared.Registration;
import com.vaadin.shared.ui.ComponentStateUtil; import com.vaadin.shared.ui.ComponentStateUtil;
import com.vaadin.shared.ui.ContentMode; import com.vaadin.shared.ui.ContentMode;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.shared.util.SharedUtil; import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.declarative.DesignAttributeHandler; import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext; import com.vaadin.ui.declarative.DesignContext;
ErrorMessage error = getErrorMessage(); ErrorMessage error = getErrorMessage();
if (null != error) { if (null != error) {
getState().errorMessage = error.getFormattedHtmlMessage(); getState().errorMessage = error.getFormattedHtmlMessage();
getState().errorLevel = error.getErrorLevel();
} else { } else {
getState().errorMessage = null; getState().errorMessage = null;
getState().errorLevel = null;
} }
} }



+ 9
- 3
server/src/main/java/com/vaadin/ui/TabSheet.java Просмотреть файл

public void setComponentError(ErrorMessage componentError) { public void setComponentError(ErrorMessage componentError) {
this.componentError = 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(); markAsDirty();
} }

+ 1
- 1
server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTest.java Просмотреть файл

import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;


import com.vaadin.server.ErrorMessage.ErrorLevel;
import com.vaadin.shared.ui.ContentMode; import com.vaadin.shared.ui.ContentMode;
import com.vaadin.server.ExternalResource; import com.vaadin.server.ExternalResource;
import com.vaadin.server.FileResource; import com.vaadin.server.FileResource;
import com.vaadin.server.Responsive; import com.vaadin.server.Responsive;
import com.vaadin.server.ThemeResource; import com.vaadin.server.ThemeResource;
import com.vaadin.server.UserError; import com.vaadin.server.UserError;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.tests.design.DeclarativeTestBase; import com.vaadin.tests.design.DeclarativeTestBase;
import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Button; import com.vaadin.ui.Button;

+ 1
- 1
server/src/test/java/com/vaadin/tests/server/component/abstractcomponent/AbstractComponentDeclarativeTestBase.java Просмотреть файл



import org.junit.Test; import org.junit.Test;


import com.vaadin.server.ErrorMessage.ErrorLevel;
import com.vaadin.server.ExternalResource; import com.vaadin.server.ExternalResource;
import com.vaadin.server.FileResource; import com.vaadin.server.FileResource;
import com.vaadin.server.ThemeResource; import com.vaadin.server.ThemeResource;
import com.vaadin.server.UserError; import com.vaadin.server.UserError;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.tests.design.DeclarativeTestBase; import com.vaadin.tests.design.DeclarativeTestBase;
import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.declarative.DesignContext; import com.vaadin.ui.declarative.DesignContext;

+ 10
- 3
shared/src/main/java/com/vaadin/shared/AbstractComponentState.java Просмотреть файл

import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.annotations.NoLayout;
import com.vaadin.shared.communication.SharedState; import com.vaadin.shared.communication.SharedState;
import com.vaadin.shared.ui.ContentMode; import com.vaadin.shared.ui.ContentMode;
import com.vaadin.shared.ui.ErrorLevel;


/** /**
* Default shared state implementation for AbstractComponent. * Default shared state implementation for AbstractComponent.
public String id = null; public String id = null;
public String primaryStyleName = 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; public String errorMessage = null;

/**
* Level of error
*
* @since 8.2
*/
public ErrorLevel errorLevel = null;

public boolean captionAsHtml = false; public boolean captionAsHtml = false;
} }

+ 58
- 0
shared/src/main/java/com/vaadin/shared/ui/ErrorLevel.java Просмотреть файл

/*
* 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();
}
}

+ 9
- 0
shared/src/main/java/com/vaadin/shared/ui/tabsheet/TabState.java Просмотреть файл



import com.vaadin.shared.ui.ContentMode; import com.vaadin.shared.ui.ContentMode;


import com.vaadin.shared.ui.ErrorLevel;

/** /**
* Shared state of a single tab in a Tabsheet or an Accordion. * Shared state of a single tab in a Tabsheet or an Accordion.
* *
public String styleName; public String styleName;
public String key; public String key;
public String componentError; public String componentError;

/**
* Represents the level of error on a tab.
*
* @since 8.2
*/
public ErrorLevel componentErrorLevel;
public String id; public String id;
public String iconAltText; public String iconAltText;



+ 1
- 1
tests/screenshots

Subproject commit 3a4a26065d36ac5fb706c159f1dd757fb52bf8eb
Subproject commit 37f67cd836df7d34469f55298bb167696338f2a5

+ 55
- 0
themes/src/main/themes/VAADIN/themes/valo/components/_combobox.scss Просмотреть файл

} }
} }


.#{$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 { .#{$primary-stylename}-suggestpopup {
@include valo-combobox-popup-style; @include valo-combobox-popup-style;
} }

+ 55
- 0
themes/src/main/themes/VAADIN/themes/valo/components/_datefield.scss Просмотреть файл

} }
} }


.#{$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 // Different widths for different resolutions
.#{$primary-stylename}-full { .#{$primary-stylename}-full {
width: round($v-font-size * 15); width: round($v-font-size * 15);

+ 67
- 3
themes/src/main/themes/VAADIN/themes/valo/components/_textfield.scss Просмотреть файл

@include valo-textfield-error-style; @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 { @if $include-additional-styles {
.#{$primary-stylename}-borderless { .#{$primary-stylename}-borderless {
* *
* @group textfield * @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; background: $bg;
color: valo-font-color($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). * 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).

+ 34
- 0
themes/src/main/themes/VAADIN/themes/valo/components/_twincolselect.scss Просмотреть файл

} }
} }


.#{$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;
}
}
} }





+ 22
- 2
themes/src/main/themes/VAADIN/themes/valo/shared/_global.scss Просмотреть файл

@include valo-error-indicator-style; @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 { .v-required-field-indicator {
color: $v-required-field-indicator-color; color: $v-required-field-indicator-color;
padding: 0 .2em; padding: 0 .2em;
* *
* @requires {mixin} valo-error-indicator-icon-style by default * @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; font-weight: 600;
width: ceil($v-unit-size/2); width: ceil($v-unit-size/2);
text-align: center; text-align: center;

+ 60
- 0
themes/src/main/themes/VAADIN/themes/valo/shared/_tooltip.scss Просмотреть файл

*/ */
$v-tooltip-error-message-font-color: $v-error-indicator-color !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. * The corner radius for tooltips.
* *
} }
} }


.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 { .v-tooltip-text {
max-height: 10em; max-height: 10em;
overflow: auto; overflow: auto;

+ 41
- 1
themes/src/main/themes/VAADIN/themes/valo/shared/_variables.scss Просмотреть файл

*/ */
$v-selection-color: $v-focus-color !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 * Color of the component error indicator and other error indications, such as the
* error style notification. * error style notification.
* @group color * @group color
* @type 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. * Color of the required indicator in field components.

+ 210
- 0
uitest/src/main/java/com/vaadin/tests/components/ErrorLevels.java Просмотреть файл

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());
}
}

+ 1
- 1
uitest/src/main/java/com/vaadin/tests/themes/valo/CommonParts.java Просмотреть файл

import com.vaadin.navigator.View; import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.server.AbstractErrorMessage; import com.vaadin.server.AbstractErrorMessage;
import com.vaadin.server.ErrorMessage.ErrorLevel;
import com.vaadin.server.Page; import com.vaadin.server.Page;
import com.vaadin.server.UserError; import com.vaadin.server.UserError;
import com.vaadin.shared.Position; import com.vaadin.shared.Position;
import com.vaadin.shared.ui.ContentMode; import com.vaadin.shared.ui.ContentMode;
import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.ui.Alignment; import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button; import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickEvent;

+ 160
- 0
uitest/src/test/java/com/vaadin/tests/components/ErrorLevelsTest.java Просмотреть файл

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;
}
}
}

+ 2
- 2
uitest/src/test/java/com/vaadin/tests/components/tabsheet/TabSheetErrorTooltipTest.java Просмотреть файл

} }


private WebElement getCurrentErrorMessage() { 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) { private void assertTooltip(String tooltip) {

Загрузка…
Отмена
Сохранить