aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormichaelvogt <michael@vaadin.com>2013-05-10 17:45:21 +0300
committerVaadin Code Review <review@vaadin.com>2013-07-03 11:18:00 +0000
commitd23c06a6145ca4c4f03377fc324e08693926873b (patch)
treed7cfe2bcbf132b4310ea56d30228933ef05d4d65
parent24b0386b4f0d3033766562573a6a322f656bf0ed (diff)
downloadvaadin-framework-d23c06a6145ca4c4f03377fc324e08693926873b.tar.gz
vaadin-framework-d23c06a6145ca4c4f03377fc324e08693926873b.zip
Accessibility for Notification (#11820)
Change-Id: Ic9c1a417fa791927897b6fcdf35a1fb4444dfd70
-rw-r--r--client/src/com/vaadin/client/ui/VNotification.java67
-rw-r--r--client/src/com/vaadin/client/ui/VOverlay.java2
-rw-r--r--server/src/com/vaadin/server/SystemMessages.java12
-rw-r--r--server/src/com/vaadin/ui/Notification.java136
-rw-r--r--server/src/com/vaadin/ui/NotificationConfiguration.java269
-rw-r--r--server/src/com/vaadin/ui/UI.java12
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/NotificationConfigurationBean.java137
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/UIState.java18
-rw-r--r--uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAria.html117
-rw-r--r--uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAria.java113
10 files changed, 872 insertions, 11 deletions
diff --git a/client/src/com/vaadin/client/ui/VNotification.java b/client/src/com/vaadin/client/ui/VNotification.java
index 7019394e3b..0ddc8bf7c5 100644
--- a/client/src/com/vaadin/client/ui/VNotification.java
+++ b/client/src/com/vaadin/client/ui/VNotification.java
@@ -21,19 +21,25 @@ import java.util.Date;
import java.util.EventObject;
import java.util.Iterator;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
+import com.vaadin.client.ui.aria.AriaHelper;
import com.vaadin.shared.Position;
+import com.vaadin.shared.ui.ui.NotificationConfigurationBean;
+import com.vaadin.shared.ui.ui.NotificationConfigurationBean.Role;
import com.vaadin.shared.ui.ui.UIConstants;
public class VNotification extends VOverlay {
@@ -149,15 +155,67 @@ public class VNotification extends VOverlay {
}
public void show(Widget widget, Position position, String style) {
- setWidget(widget);
+ NotificationConfigurationBean styleSetup = getUiState(style);
+ setWaiAriaRole(styleSetup);
+
+ FlowPanel panel = new FlowPanel();
+ if (styleSetup.hasAssistivePrefix()) {
+ panel.add(new Label(styleSetup.getAssistivePrefix()));
+ AriaHelper.setVisibleForAssistiveDevicesOnly(panel.getElement(),
+ true);
+ }
+
+ panel.add(widget);
+
+ if (styleSetup.hasAssistivePostfix()) {
+ panel.add(new Label(styleSetup.getAssistivePostfix()));
+ AriaHelper.setVisibleForAssistiveDevicesOnly(panel.getElement(),
+ true);
+ }
+ setWidget(panel);
show(position, style);
}
public void show(String html, Position position, String style) {
- setWidget(new HTML(html));
+ NotificationConfigurationBean styleSetup = getUiState(style);
+ String assistiveDeviceOnlyStyle = AriaHelper.ASSISTIVE_DEVICE_ONLY_STYLE;
+
+ setWaiAriaRole(styleSetup);
+
+ String type = "";
+ String usage = "";
+
+ if (styleSetup != null && styleSetup.hasAssistivePrefix()) {
+ type = "<span class='" + assistiveDeviceOnlyStyle + "'>"
+ + styleSetup.getAssistivePrefix() + "</span>";
+ }
+
+ if (styleSetup != null && styleSetup.hasAssistivePostfix()) {
+ usage = "<span class='" + assistiveDeviceOnlyStyle + "'>"
+ + styleSetup.getAssistivePostfix() + "</span>";
+ }
+
+ setWidget(new HTML(type + html + usage));
show(position, style);
}
+ private NotificationConfigurationBean getUiState(String style) {
+ NotificationConfigurationBean styleSetup = getApplicationConnection()
+ .getUIConnector().getState().notificationConfiguration.setup
+ .get(style);
+ return styleSetup;
+ }
+
+ private void setWaiAriaRole(NotificationConfigurationBean styleSetup) {
+ Roles.getAlertRole().set(getElement());
+
+ if (styleSetup != null && styleSetup.getAssistiveRole() != null) {
+ if (Role.STATUS == styleSetup.getAssistiveRole()) {
+ Roles.getStatusRole().set(getElement());
+ }
+ }
+ }
+
public void show(Position position, String style) {
setOpacity(getElement(), startOpacity);
if (style != null) {
@@ -377,7 +435,8 @@ public class VNotification extends VOverlay {
final String parsedUri = client
.translateVaadinUri(notification
.getStringAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_ICON));
- html += "<img src=\"" + Util.escapeAttribute(parsedUri) + "\" />";
+ html += "<img src=\"" + Util.escapeAttribute(parsedUri)
+ + "\" alt=\"\" />";
}
if (notification
.hasAttribute(UIConstants.ATTRIBUTE_NOTIFICATION_CAPTION)) {
@@ -417,6 +476,8 @@ public class VNotification extends VOverlay {
public static VNotification createNotification(int delayMsec, Widget owner) {
final VNotification notification = GWT.create(VNotification.class);
+ notification.setWaiAriaRole(null);
+
notification.delayMsec = delayMsec;
if (BrowserInfo.get().isTouchDevice()) {
new Timer() {
diff --git a/client/src/com/vaadin/client/ui/VOverlay.java b/client/src/com/vaadin/client/ui/VOverlay.java
index ced476f9dd..206e26b960 100644
--- a/client/src/com/vaadin/client/ui/VOverlay.java
+++ b/client/src/com/vaadin/client/ui/VOverlay.java
@@ -172,7 +172,7 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
*
* See default theme 'shadow.css' for implementation example.
*/
- private static final String SHADOW_HTML = "<div class=\"top-left\"></div><div class=\"top\"></div><div class=\"top-right\"></div><div class=\"left\"></div><div class=\"center\"></div><div class=\"right\"></div><div class=\"bottom-left\"></div><div class=\"bottom\"></div><div class=\"bottom-right\"></div>";
+ private static final String SHADOW_HTML = "<div aria-hidden=\"true\" class=\"top-left\"></div><div class=\"top\"></div><div class=\"top-right\"></div><div class=\"left\"></div><div class=\"center\"></div><div class=\"right\"></div><div class=\"bottom-left\"></div><div class=\"bottom\"></div><div class=\"bottom-right\"></div>";
/**
* Matches {@link PopupPanel}.ANIMATION_DURATION
diff --git a/server/src/com/vaadin/server/SystemMessages.java b/server/src/com/vaadin/server/SystemMessages.java
index 5e0fde1d4a..299c725207 100644
--- a/server/src/com/vaadin/server/SystemMessages.java
+++ b/server/src/com/vaadin/server/SystemMessages.java
@@ -63,32 +63,32 @@ public class SystemMessages implements Serializable {
protected String sessionExpiredURL = null;
protected boolean sessionExpiredNotificationEnabled = true;
protected String sessionExpiredCaption = "Session Expired";
- protected String sessionExpiredMessage = "Take note of any unsaved data, and <u>click here</u> to continue.";
+ protected String sessionExpiredMessage = "Take note of any unsaved data, and <u>click here</u> or press ESC key to continue.";
protected String communicationErrorURL = null;
protected boolean communicationErrorNotificationEnabled = true;
protected String communicationErrorCaption = "Communication problem";
- protected String communicationErrorMessage = "Take note of any unsaved data, and <u>click here</u> to continue.";
+ protected String communicationErrorMessage = "Take note of any unsaved data, and <u>click here</u> or press ESC to continue.";
protected String authenticationErrorURL = null;
protected boolean authenticationErrorNotificationEnabled = true;
protected String authenticationErrorCaption = "Authentication problem";
- protected String authenticationErrorMessage = "Take note of any unsaved data, and <u>click here</u> to continue.";
+ protected String authenticationErrorMessage = "Take note of any unsaved data, and <u>click here</u> or press ESC to continue.";
protected String internalErrorURL = null;
protected boolean internalErrorNotificationEnabled = true;
protected String internalErrorCaption = "Internal error";
- protected String internalErrorMessage = "Please notify the administrator.<br/>Take note of any unsaved data, and <u>click here</u> to continue.";
+ protected String internalErrorMessage = "Please notify the administrator.<br/>Take note of any unsaved data, and <u>click here</u> or press ESC to continue.";
protected String outOfSyncURL = null;
protected boolean outOfSyncNotificationEnabled = true;
protected String outOfSyncCaption = "Out of sync";
- protected String outOfSyncMessage = "Something has caused us to be out of sync with the server.<br/>Take note of any unsaved data, and <u>click here</u> to re-sync.";
+ protected String outOfSyncMessage = "Something has caused us to be out of sync with the server.<br/>Take note of any unsaved data, and <u>click here</u> or press ESC to re-sync.";
protected String cookiesDisabledURL = null;
protected boolean cookiesDisabledNotificationEnabled = true;
protected String cookiesDisabledCaption = "Cookies disabled";
- protected String cookiesDisabledMessage = "This application requires cookies to function.<br/>Please enable cookies in your browser and <u>click here</u> to try again.";
+ protected String cookiesDisabledMessage = "This application requires cookies to function.<br/>Please enable cookies in your browser and <u>click here</u> or press ESC to try again.";
/**
* Use {@link CustomizedSystemMessages} to customize
diff --git a/server/src/com/vaadin/ui/Notification.java b/server/src/com/vaadin/ui/Notification.java
index cf1d03ab5c..f9bb1521e7 100644
--- a/server/src/com/vaadin/ui/Notification.java
+++ b/server/src/com/vaadin/ui/Notification.java
@@ -21,6 +21,7 @@ import java.io.Serializable;
import com.vaadin.server.Page;
import com.vaadin.server.Resource;
import com.vaadin.shared.Position;
+import com.vaadin.shared.ui.ui.NotificationConfigurationBean.Role;
/**
* A notification message, used to display temporary messages to the user - for
@@ -190,21 +191,32 @@ public class Notification implements Serializable {
case WARNING_MESSAGE:
delayMsec = 1500;
styleName = "warning";
+ setNavigationConfiguration("Warning: ", "", Role.ALERT);
break;
case ERROR_MESSAGE:
delayMsec = -1;
styleName = "error";
+ setNavigationConfiguration("Error: ", " - close with ESC",
+ Role.ALERT);
break;
case TRAY_NOTIFICATION:
delayMsec = 3000;
position = Position.BOTTOM_RIGHT;
styleName = "tray";
-
+ setNavigationConfiguration("Info: ", "", Role.STATUS);
+ break;
case HUMANIZED_MESSAGE:
default:
+ styleName = "humanized";
+ setNavigationConfiguration("Info: ", "", Role.ALERT);
break;
}
+ }
+ private void setNavigationConfiguration(String prefix, String postfix,
+ Role ariaRole) {
+ UI.getCurrent().getNotificationConfiguration()
+ .setStyleConfiguration(styleName, prefix, postfix, ariaRole);
}
/**
@@ -322,6 +334,128 @@ public class Notification implements Serializable {
}
/**
+ * Sets the accessibility prefix for a notification type.
+ *
+ * This prefix is read to assistive device users before the content of the
+ * notification, but not visible on the page.
+ *
+ * @param type
+ * Type of the notification
+ * @param prefix
+ * String that is placed before the notification content
+ */
+ public void setAssistivePrefixForType(Type type, String prefix) {
+ UI.getCurrent().getNotificationConfiguration()
+ .setAssistivePrefixForStyle(getStyle(type), prefix);
+ }
+
+ /**
+ * Gets the accessibility prefix for a notification type.
+ *
+ * This prefix is read to assistive device users before the content of the
+ * notification, but not visible on the page.
+ *
+ * @param type
+ * Type of the notification
+ * @return The accessibility prefix for the provided notification type
+ */
+ public String getAssistivePrefixForType(Type type) {
+ return UI.getCurrent().getNotificationConfiguration()
+ .getAssistivePrefixForStyle(getStyle(type));
+ }
+
+ /**
+ * Sets the accessibility postfix for a notification type.
+ *
+ * This postfix is read to assistive device users after the content of the
+ * notification, but not visible on the page.
+ *
+ * @param type
+ * Type of the notification
+ * @param postfix
+ * String that is placed after the notification content
+ */
+ public void setAssistivePostfixForType(Type type, String postfix) {
+ UI.getCurrent().getNotificationConfiguration()
+ .setAssistivePostfixForStyle(getStyle(type), postfix);
+ }
+
+ /**
+ * Gets the accessibility postfix for a notification type.
+ *
+ * This postfix is read to assistive device users after the content of the
+ * notification, but not visible on the page.
+ *
+ * @param type
+ * Type of the notification
+ * @return The accessibility postfix for the provided notification type
+ */
+ public String getAssistivePostfixForType(Type type) {
+ return UI.getCurrent().getNotificationConfiguration()
+ .getAssistivePostfixForStyle(getStyle(type));
+ }
+
+ /**
+ * Sets the WAI-ARIA role for a notification type.
+ *
+ * This role defines how an assistive device handles a notification.
+ * Available roles are alert and status (@see <a
+ * href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
+ * Model</a>).
+ *
+ * The default role is alert.
+ *
+ * @param type
+ * Type of the notification
+ * @param role
+ * Role to set for the notification type
+ */
+ public void setAssistiveRoleForType(Type type, Role role) {
+ UI.getCurrent().getNotificationConfiguration()
+ .setAssistiveRoleForStyle(getStyle(type), role);
+ }
+
+ /**
+ * Gets the WAI-ARIA role for a notification type.
+ *
+ * This role defines how an assistive device handles a notification.
+ * Available roles are alert and status (@see <a
+ * href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
+ * Model</a>)
+ *
+ * The default role is alert.
+ *
+ * @param type
+ * Type of the notification
+ * @return Role to set for the notification type
+ */
+ public Role getAssistiveRoleForType(Type type) {
+ return UI.getCurrent().getNotificationConfiguration()
+ .getAssistiveRoleForStyle(getStyle(type));
+ }
+
+ private String getStyle(Type type) {
+ String style = "";
+
+ switch (type) {
+ case WARNING_MESSAGE:
+ style = "warning";
+ break;
+ case ERROR_MESSAGE:
+ style = "error";
+ break;
+ case TRAY_NOTIFICATION:
+ style = "tray";
+ case HUMANIZED_MESSAGE:
+ default:
+ style = "humanized";
+ break;
+ }
+
+ return style;
+ }
+
+ /**
* Sets whether html is allowed in the caption and description. If set to
* true, the texts are passed to the browser as html and the developer is
* responsible for ensuring no harmful html is used. If set to false, the
diff --git a/server/src/com/vaadin/ui/NotificationConfiguration.java b/server/src/com/vaadin/ui/NotificationConfiguration.java
new file mode 100644
index 0000000000..52d3e76d63
--- /dev/null
+++ b/server/src/com/vaadin/ui/NotificationConfiguration.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2000-2013 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.ui;
+
+import java.io.Serializable;
+
+import com.vaadin.shared.ui.ui.NotificationConfigurationBean;
+import com.vaadin.shared.ui.ui.NotificationConfigurationBean.Role;
+import com.vaadin.shared.ui.ui.UIState.NotificationConfigurationState;
+
+/**
+ * Provides methods for configuring the notification.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public interface NotificationConfiguration extends Serializable {
+ public void setStyleConfiguration(String style, String prefix,
+ String postfix, Role ariaRole);
+
+ /**
+ * Returns the complete configuration object for the given notification
+ * style.
+ *
+ * @param style
+ * String of the notification style to return
+ * @return The notification configuration object
+ */
+ public NotificationConfigurationBean getStyleConfiguration(String style);
+
+ /**
+ * Sets the accessibility prefix for the given notification style.
+ *
+ * This prefix is read to assistive device users in front of the content of
+ * the notification, but not visible on the page.
+ *
+ * @param style
+ * String of the notification style
+ * @param prefix
+ * String that is placed before the notification content
+ */
+ public void setAssistivePrefixForStyle(String style, String prefix);
+
+ /**
+ * Returns the accessibility prefix for the given notification style.
+ *
+ * This prefix is read to assistive device users in front of the content of
+ * the notification, but not visible on the page.
+ *
+ * @param style
+ * String of the notification style
+ * @return The prefix of the provided notification style
+ */
+ public String getAssistivePrefixForStyle(String style);
+
+ /**
+ * Sets the accessibility postfix for the given notification style.
+ *
+ * This postfix is read to assistive device users after the content of the
+ * notification, but not visible on the page.
+ *
+ * @param style
+ * String of the notification style
+ * @param postfix
+ * String that is placed after the notification content
+ */
+ public void setAssistivePostfixForStyle(String style, String postfix);
+
+ /**
+ * Returns the accessibility postfix for the given notification style.
+ *
+ * This postfix is read to assistive device users after the content of the
+ * notification, but not visible on the page.
+ *
+ * @param style
+ * String of the notification style
+ * @return The postfix of the provided notification style
+ */
+ public String getAssistivePostfixForStyle(String style);
+
+ /**
+ * Sets the WAI-ARIA role for a notification style.
+ *
+ * This role defines how an assistive device handles a notification.
+ * Available roles are alert, alertdialog and status (@see <a
+ * href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
+ * Model</a>)
+ *
+ * The default role is alert.
+ *
+ * @param style
+ * String of the notification style
+ * @param role
+ * Role to set for the notification type
+ */
+ public void setAssistiveRoleForStyle(String style, Role role);
+
+ /**
+ * Returns the WAI-ARIA role for a notification style.
+ *
+ * This role defines how an assistive device handles a notification.
+ * Available roles are alert, alertdialog and status (@see <a
+ * href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
+ * Model</a> )
+ *
+ * The default role is alert.
+ *
+ * @param style
+ * String of the notification style
+ * @return The current Role for the notification type
+ */
+ public Role getAssistiveRoleForStyle(String style);
+}
+
+class NotificationConfigurationImpl implements NotificationConfiguration {
+
+ private UI ui;
+
+ public NotificationConfigurationImpl(UI ui) {
+ this.ui = ui;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.NotificationConfiguration#setStyleConfiguration(java.lang
+ * .String, java.lang.String, java.lang.String,
+ * com.vaadin.ui.NotificationConfiguration.Role)
+ */
+ @Override
+ public void setStyleConfiguration(String style, String prefix,
+ String postfix, Role ariaRole) {
+ getState().setup.put(style, new NotificationConfigurationBean(prefix,
+ postfix, ariaRole));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.NotificationConfiguration#getStyleConfiguration(java.lang
+ * .String)
+ */
+ @Override
+ public NotificationConfigurationBean getStyleConfiguration(String style) {
+ return getState(false).setup.get(style);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.NotificationConfiguration#setStylePrefix(java.lang.String,
+ * java.lang.String)
+ */
+ @Override
+ public void setAssistivePrefixForStyle(String style, String prefix) {
+ getConfigurationBean(style).setAssistivePrefix(prefix);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.NotificationConfiguration#getStylePrefix(java.lang.String)
+ */
+ @Override
+ public String getAssistivePrefixForStyle(String style) {
+ NotificationConfigurationBean styleSetup = getState().setup.get(style);
+ if (styleSetup != null) {
+ return styleSetup.getAssistivePrefix();
+ }
+
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.NotificationConfiguration#setStylePostfix(com.vaadin.ui
+ * .Notification.Type, java.lang.String)
+ */
+ @Override
+ public void setAssistivePostfixForStyle(String style, String postfix) {
+ getConfigurationBean(style).setAssistivePostfix(postfix);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.NotificationConfiguration#getStylePostfix(com.vaadin.ui
+ * .Notification.Type)
+ */
+ @Override
+ public String getAssistivePostfixForStyle(String style) {
+ NotificationConfigurationBean styleSetup = getState().setup.get(style);
+ if (styleSetup != null) {
+ return styleSetup.getAssistivePostfix();
+ }
+
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.NotificationConfiguration#setStyleRole(com.vaadin.ui.
+ * Notification.Type, com.vaadin.ui.NotificationConfiguration.Role)
+ */
+ @Override
+ public void setAssistiveRoleForStyle(String style, Role role) {
+ getConfigurationBean(style).setAssistiveRole(role);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.NotificationConfiguration#getStyleRole(com.vaadin.ui.
+ * Notification.Type)
+ */
+ @Override
+ public Role getAssistiveRoleForStyle(String style) {
+ NotificationConfigurationBean styleSetup = getState().setup.get(style);
+ if (styleSetup != null) {
+ return styleSetup.getAssistiveRole();
+ }
+
+ return null;
+ }
+
+ private NotificationConfigurationBean getConfigurationBean(String style) {
+ NotificationConfigurationBean styleSetup = getState().setup.get(style);
+ if (styleSetup == null) {
+ styleSetup = new NotificationConfigurationBean();
+ getState().setup.put(style, styleSetup);
+ }
+
+ return styleSetup;
+ }
+
+ private NotificationConfigurationState getState() {
+ return ui.getState().notificationConfiguration;
+ }
+
+ private NotificationConfigurationState getState(boolean markAsDirty) {
+ return ui.getState(markAsDirty).notificationConfiguration;
+ }
+
+}
diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java
index e0811e51f7..2138edd6ac 100644
--- a/server/src/com/vaadin/ui/UI.java
+++ b/server/src/com/vaadin/ui/UI.java
@@ -218,6 +218,9 @@ public abstract class UI extends AbstractSingleComponentContainer implements
private PushConfiguration pushConfiguration = new PushConfigurationImpl(
this);
+ private NotificationConfiguration notificationConfiguration = new NotificationConfigurationImpl(
+ this);
+
/**
* Creates a new empty UI without a caption. The content of the UI must be
* set by calling {@link #setContent(Component)} before using the UI.
@@ -1282,6 +1285,15 @@ public abstract class UI extends AbstractSingleComponentContainer implements
}
/**
+ * Retrieves the object used for configuring notifications.
+ *
+ * @return The instance used for notification configuration
+ */
+ public NotificationConfiguration getNotificationConfiguration() {
+ return notificationConfiguration;
+ }
+
+ /**
* Retrieves the object used for configuring the loading indicator.
*
* @return The instance used for configuring the loading indicator
diff --git a/shared/src/com/vaadin/shared/ui/ui/NotificationConfigurationBean.java b/shared/src/com/vaadin/shared/ui/ui/NotificationConfigurationBean.java
new file mode 100644
index 0000000000..05a1706763
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/ui/NotificationConfigurationBean.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2000-2013 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.ui;
+
+import java.io.Serializable;
+
+/**
+ * Holds configuration information for a notification type.
+ *
+ * @author Vaadin Ltd
+ */
+public class NotificationConfigurationBean implements Serializable {
+ /**
+ * Available WAI-ARIA roles for a notification.
+ */
+ public enum Role {
+ ALERT, STATUS
+ };
+
+ private String prefix;
+ private String postfix;
+ private Role role = Role.ALERT;
+
+ public NotificationConfigurationBean() {
+ }
+
+ public NotificationConfigurationBean(String prefix, String postfix,
+ Role role) {
+ this.prefix = prefix;
+ this.postfix = postfix;
+ this.role = role;
+ }
+
+ /**
+ * Returns the accessibility prefix, which is placed before the notification
+ * content.
+ *
+ * @return the prefix
+ */
+ public String getAssistivePrefix() {
+ return prefix;
+ }
+
+ /**
+ * Sets the accessibility prefix, which is placed before the notification
+ * content.
+ *
+ * @param pefix
+ * the prefix to set
+ */
+ public void setAssistivePrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ /**
+ * Checks if an accessibility prefix is set.
+ *
+ * @return true when assistivePrefix is not null and has a length > 0, false
+ * otherwise
+ */
+ public boolean hasAssistivePrefix() {
+ return prefix != null && !prefix.isEmpty();
+ }
+
+ /**
+ * Returns the accessibility postfix, which is placed after the notification
+ * content.
+ *
+ * @return the postfix
+ */
+ public String getAssistivePostfix() {
+ return postfix;
+ }
+
+ /**
+ * Sets the accessibility postfix, which is placed after the notification
+ * content.
+ *
+ * @param postfix
+ * the postfix to set
+ */
+ public void setAssistivePostfix(String postfix) {
+ this.postfix = postfix;
+ }
+
+ /**
+ * Checks if an accessibility postfix is set.
+ *
+ * @return true when postfix is not null and has a length > 0, false
+ * otherwise
+ */
+ public boolean hasAssistivePostfix() {
+ return postfix != null && !postfix.isEmpty();
+ }
+
+ /**
+ * Returns the WAI-ARIA role that defines how an assistive device will
+ * inform the user about a notification.
+ *
+ * @return the role
+ */
+ public Role getAssistiveRole() {
+ return role;
+ }
+
+ /**
+ * Sets the WAI-ARIA role that defines how an assistive device will inform
+ * the user about a notification.
+ *
+ * Available roles are alert, alertdialog and status (@see <a
+ * href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
+ * Model</a>).
+ *
+ * @param role
+ * the role to set
+ */
+ public void setAssistiveRole(Role role) {
+ this.role = role;
+ }
+}
diff --git a/shared/src/com/vaadin/shared/ui/ui/UIState.java b/shared/src/com/vaadin/shared/ui/ui/UIState.java
index 8d042a835f..4cde452a2b 100644
--- a/shared/src/com/vaadin/shared/ui/ui/UIState.java
+++ b/shared/src/com/vaadin/shared/ui/ui/UIState.java
@@ -23,10 +23,12 @@ import java.util.Map;
import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.TabIndexState;
+import com.vaadin.shared.ui.ui.NotificationConfigurationBean.Role;
public class UIState extends TabIndexState {
public TooltipConfigurationState tooltipConfiguration = new TooltipConfigurationState();
public LoadingIndicatorConfigurationState loadingIndicatorConfiguration = new LoadingIndicatorConfigurationState();
+ public NotificationConfigurationState notificationConfiguration = new NotificationConfigurationState();
public int pollInterval = -1;
// Informing users of assistive devices, that the content of this container
@@ -48,6 +50,22 @@ public class UIState extends TabIndexState {
public int maxWidth = 500;
}
+ public static class NotificationConfigurationState implements Serializable {
+ public Map<String, NotificationConfigurationBean> setup = new HashMap<String, NotificationConfigurationBean>();
+ {
+ setup.put("error", new NotificationConfigurationBean("Error: ",
+ " - close with ESC-key", Role.ALERT));
+ setup.put("warning", new NotificationConfigurationBean("Warning: ",
+ null, Role.ALERT));
+ setup.put("humanized", new NotificationConfigurationBean("Info: ",
+ null, Role.ALERT));
+ setup.put("tray", new NotificationConfigurationBean("Status: ",
+ null, Role.STATUS));
+ setup.put("assistive", new NotificationConfigurationBean("Note: ",
+ null, Role.STATUS));
+ };
+ }
+
public static class PushConfigurationState implements Serializable {
public static final String TRANSPORT_PARAM = "transport";
public static final String FALLBACK_TRANSPORT_PARAM = "fallbackTransport";
diff --git a/uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAria.html b/uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAria.html
new file mode 100644
index 0000000000..aa13b9e637
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAria.html
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>NotificationsWaiAria</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">NotificationsWaiAria</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.notification.NotificationsWaiAria?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTextField[0]</td>
+ <td>Prefix:</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VTextField[0]</td>
+ <td>- press ESC to close</td>
+</tr>
+<tr>
+ <td>select</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VNativeSelect[0]/domChild[0]</td>
+ <td>label=ALERT</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::Root/VNotification[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::Root/VNotification[0]@role</td>
+ <td>alert</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::Root/VNotification[0]/domChild[0]/domChild[0]/domChild[0]@class</td>
+ <td>v-assistive-device-only</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::Root/VNotification[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>Prefix:</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::Root/VNotification[0]/domChild[0]/domChild[0]/domChild[2]@class</td>
+ <td>v-assistive-device-only</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::Root/VNotification[0]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>- press ESC to close</td>
+</tr>
+<tr>
+ <td>closeNotification</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::Root/VNotification[0]</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>select</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VNativeSelect[0]/domChild[0]</td>
+ <td>label=STATUS</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=/html/body/div[2]/div@role</td>
+ <td>status</td>
+</tr>
+<tr>
+ <td>closeNotification</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::Root/VNotification[0]</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTextField[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VTextField[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertElementNotPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsnotificationNotificationsWaiAria::Root/VNotification[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td></td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAria.java b/uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAria.java
new file mode 100644
index 0000000000..a8861d40de
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/notification/NotificationsWaiAria.java
@@ -0,0 +1,113 @@
+package com.vaadin.tests.components.notification;
+
+import com.vaadin.data.Item;
+import com.vaadin.server.Page;
+import com.vaadin.shared.ui.ui.NotificationConfigurationBean.Role;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.Notification;
+import com.vaadin.ui.Notification.Type;
+import com.vaadin.ui.TextArea;
+import com.vaadin.ui.TextField;
+
+public class NotificationsWaiAria extends TestBase {
+
+ private static final String CAPTION = "CAPTION";
+ private static final String ROLE = "ROLE";
+
+ private TextField prefix;
+ private TextField postfix;
+ private NativeSelect role;
+
+ private TextArea tf;
+ private ComboBox type;
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void setup() {
+ prefix = new TextField("Prefix", "Info");
+ addComponent(prefix);
+
+ postfix = new TextField("Postfix",
+ " - closes automatically after 10 seconds");
+ addComponent(postfix);
+
+ role = new NativeSelect("Role");
+ role.addItem(Role.ALERT);
+ role.addItem(Role.STATUS);
+ role.setValue(role.getItemIds().iterator().next());
+ addComponent(role);
+
+ tf = new TextArea("Text", "Hello world");
+ tf.setRows(10);
+ addComponent(tf);
+ type = new ComboBox();
+ type.setNullSelectionAllowed(false);
+ type.addContainerProperty(CAPTION, String.class, "");
+
+ type.setItemCaptionPropertyId(CAPTION);
+
+ Item item = type.addItem(Notification.TYPE_HUMANIZED_MESSAGE);
+ item.getItemProperty(CAPTION).setValue("Humanized");
+
+ item = type.addItem(Notification.TYPE_ERROR_MESSAGE);
+ item.getItemProperty(CAPTION).setValue("Error");
+
+ item = type.addItem(Notification.TYPE_WARNING_MESSAGE);
+ item.getItemProperty(CAPTION).setValue("Warning");
+
+ item = type.addItem(Notification.TYPE_TRAY_NOTIFICATION);
+ item.getItemProperty(CAPTION).setValue("Tray");
+
+ type.setValue(type.getItemIds().iterator().next());
+ addComponent(type);
+
+ Button showNotification = new Button("Show notification",
+ new SettingHandler());
+ addComponent(showNotification);
+
+ Button showDefaultNotification = new Button("Default notification",
+ new DefaultHandler());
+ addComponent(showDefaultNotification);
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Generic test case for notifications";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ private class SettingHandler implements ClickListener {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Type typeValue = (Type) type.getValue();
+
+ Notification n = new Notification(tf.getValue(), typeValue);
+ n.setHtmlContentAllowed(true);
+ n.setAssistivePrefixForType(typeValue, prefix.getValue());
+ n.setAssistivePostfixForType(typeValue, postfix.getValue());
+ n.setAssistiveRoleForType(typeValue, (Role) role.getValue());
+
+ n.show(Page.getCurrent());
+ }
+ }
+
+ private class DefaultHandler implements ClickListener {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Notification n = new Notification(tf.getValue(),
+ (Type) type.getValue());
+ n.setHtmlContentAllowed(true);
+ n.show(Page.getCurrent());
+ }
+ }
+}