summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/com/vaadin/client/ApplicationConnection.java26
-rw-r--r--client/src/com/vaadin/client/BrowserInfo.java9
-rw-r--r--client/src/com/vaadin/client/VTooltip.java5
-rw-r--r--client/src/com/vaadin/client/ui/VContextMenu.java36
-rw-r--r--client/src/com/vaadin/client/ui/VFormLayout.java2
-rw-r--r--client/src/com/vaadin/client/ui/VOverlay.java65
-rw-r--r--client/src/com/vaadin/client/ui/VScrollTable.java16
-rw-r--r--client/src/com/vaadin/client/ui/VTextualDate.java6
-rw-r--r--client/src/com/vaadin/client/ui/ui/UIConnector.java25
-rwxr-xr-xscripts/automerge7.sh26
-rw-r--r--server/src/com/vaadin/server/Page.java53
-rw-r--r--server/src/com/vaadin/ui/AbstractField.java11
-rw-r--r--server/src/com/vaadin/ui/UI.java36
-rw-r--r--server/tests/src/com/vaadin/server/VaadinSessionTest.java2
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/PageState.java33
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/UIState.java11
-rw-r--r--uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutWithNonIntegerWidth.java53
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.html10
-rw-r--r--uitest/src/com/vaadin/tests/components/window/CenteredInVisualViewport.java66
19 files changed, 467 insertions, 24 deletions
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index 1faf39394d..4141f9f2dc 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -27,6 +27,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import com.google.gwt.aria.client.LiveValue;
+import com.google.gwt.aria.client.RelevantValue;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.Duration;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
@@ -81,6 +84,7 @@ import com.vaadin.client.ui.AbstractConnector;
import com.vaadin.client.ui.VContextMenu;
import com.vaadin.client.ui.VNotification;
import com.vaadin.client.ui.VNotification.HideEvent;
+import com.vaadin.client.ui.VOverlay;
import com.vaadin.client.ui.dd.VDragAndDropManager;
import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.client.ui.window.WindowConnector;
@@ -456,6 +460,15 @@ public class ApplicationConnection {
webkitMaybeIgnoringRequests = true;
}
});
+
+ // Ensure the overlay container is added to the dom and set as a live
+ // area for assistive devices
+ Element overlayContainer = VOverlay.getOverlayContainer(this);
+ Roles.getAlertRole().setAriaLiveProperty(overlayContainer,
+ LiveValue.ASSERTIVE);
+ setOverlayContainerLabel(getUIConnector().getState().overlayContainerLabel);
+ Roles.getAlertRole().setAriaRelevantProperty(overlayContainer,
+ RelevantValue.ADDITIONS);
}
/**
@@ -3421,4 +3434,17 @@ public class ApplicationConnection {
public void handlePushMessage(String message) {
handleJSONText(message, 200);
}
+
+ /**
+ * Set the label of the container element, where tooltip, notification and
+ * dialgs are added to.
+ *
+ * @param overlayContainerLabel
+ * label for the container
+ */
+ public void setOverlayContainerLabel(String overlayContainerLabel) {
+ Roles.getAlertRole().setAriaLabelProperty(
+ VOverlay.getOverlayContainer(this),
+ getUIConnector().getState().overlayContainerLabel);
+ }
}
diff --git a/client/src/com/vaadin/client/BrowserInfo.java b/client/src/com/vaadin/client/BrowserInfo.java
index 73f3a68193..b3490c3ca4 100644
--- a/client/src/com/vaadin/client/BrowserInfo.java
+++ b/client/src/com/vaadin/client/BrowserInfo.java
@@ -396,10 +396,19 @@ public class BrowserInfo {
&& (getOperatingSystemMajorVersion() == 3 || getOperatingSystemMajorVersion() == 4);
}
+ public boolean isAndroid23() {
+ return isAndroid() && getOperatingSystemMajorVersion() == 2
+ && getOperatingSystemMinorVersion() == 3;
+ }
+
private int getOperatingSystemMajorVersion() {
return browserDetails.getOperatingSystemMajorVersion();
}
+ private int getOperatingSystemMinorVersion() {
+ return browserDetails.getOperatingSystemMinorVersion();
+ }
+
/**
* Returns the browser major version e.g., 3 for Firefox 3.5, 4 for Chrome
* 4, 8 for Internet Explorer 8.
diff --git a/client/src/com/vaadin/client/VTooltip.java b/client/src/com/vaadin/client/VTooltip.java
index 61d155d668..6191821988 100644
--- a/client/src/com/vaadin/client/VTooltip.java
+++ b/client/src/com/vaadin/client/VTooltip.java
@@ -16,7 +16,6 @@
package com.vaadin.client;
import com.google.gwt.aria.client.Id;
-import com.google.gwt.aria.client.LiveValue;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
@@ -86,10 +85,8 @@ public class VTooltip extends VOverlay {
DOM.appendChild(layoutElement, description);
setSinkShadowEvents(true);
- // WAI-ARIA additions
+ // Used to bind the tooltip to the owner for assistive devices
layoutElement.setId(uniqueId);
- Roles.getTooltipRole().setAriaLiveProperty(getElement(),
- LiveValue.POLITE);
description.setId(DOM.createUniqueId());
Roles.getTooltipRole().set(layoutElement);
diff --git a/client/src/com/vaadin/client/ui/VContextMenu.java b/client/src/com/vaadin/client/ui/VContextMenu.java
index e601c8027a..02ee5b07c5 100644
--- a/client/src/com/vaadin/client/ui/VContextMenu.java
+++ b/client/src/com/vaadin/client/ui/VContextMenu.java
@@ -29,12 +29,17 @@ import com.google.gwt.event.dom.client.HasBlurHandlers;
import com.google.gwt.event.dom.client.HasFocusHandlers;
import com.google.gwt.event.dom.client.HasKeyDownHandlers;
import com.google.gwt.event.dom.client.HasKeyPressHandlers;
+import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
@@ -43,6 +48,7 @@ import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.impl.FocusImpl;
import com.vaadin.client.Focusable;
import com.vaadin.client.Util;
@@ -57,6 +63,8 @@ public class VContextMenu extends VOverlay implements SubPartAware {
private int top;
+ private Element focusedElement;
+
private VLazyExecutor delayedImageLoadExecutioner = new VLazyExecutor(100,
new ScheduledCommand() {
@Override
@@ -77,6 +85,20 @@ public class VContextMenu extends VOverlay implements SubPartAware {
setWidget(menu);
setStyleName("v-contextmenu");
getElement().setId(DOM.createUniqueId());
+
+ addCloseHandler(new CloseHandler<PopupPanel>() {
+ @Override
+ public void onClose(CloseEvent<PopupPanel> event) {
+ Element currentFocus = Util.getFocusedElement();
+ if (focusedElement != null
+ && (currentFocus == null
+ || menu.getElement().isOrHasChild(currentFocus) || RootPanel
+ .getBodyElement().equals(currentFocus))) {
+ focusedElement.focus();
+ focusedElement = null;
+ }
+ }
+ });
}
protected void imagesLoaded() {
@@ -117,6 +139,10 @@ public class VContextMenu extends VOverlay implements SubPartAware {
// Attach onload listeners to all images
Util.sinkOnloadForImages(menu.getElement());
+ // Store the currently focused element, which will be re-focused when
+ // context menu is closed
+ focusedElement = Util.getFocusedElement();
+
setPopupPositionAndShow(new PositionCallback() {
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
@@ -170,10 +196,11 @@ public class VContextMenu extends VOverlay implements SubPartAware {
*/
class CMenuBar extends MenuBar implements HasFocusHandlers,
HasBlurHandlers, HasKeyDownHandlers, HasKeyPressHandlers,
- Focusable, LoadHandler {
+ Focusable, LoadHandler, KeyUpHandler {
public CMenuBar() {
super(true);
addDomHandler(this, LoadEvent.getType());
+ addDomHandler(this, KeyUpEvent.getType());
}
@Override
@@ -242,6 +269,13 @@ public class VContextMenu extends VOverlay implements SubPartAware {
delayedImageLoadExecutioner.trigger();
}
+ @Override
+ public void onKeyUp(KeyUpEvent event) {
+ // Allow to close context menu with ESC
+ if (event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
+ hide();
+ }
+ }
}
@Override
diff --git a/client/src/com/vaadin/client/ui/VFormLayout.java b/client/src/com/vaadin/client/ui/VFormLayout.java
index b2dc13178e..6c2661d1d8 100644
--- a/client/src/com/vaadin/client/ui/VFormLayout.java
+++ b/client/src/com/vaadin/client/ui/VFormLayout.java
@@ -95,6 +95,8 @@ public class VFormLayout extends SimplePanel {
public VFormLayoutTable() {
DOM.setElementProperty(getElement(), "cellPadding", "0");
DOM.setElementProperty(getElement(), "cellSpacing", "0");
+
+ Roles.getPresentationRole().set(getElement());
}
/*
diff --git a/client/src/com/vaadin/client/ui/VOverlay.java b/client/src/com/vaadin/client/ui/VOverlay.java
index d35201460e..9e809758ca 100644
--- a/client/src/com/vaadin/client/ui/VOverlay.java
+++ b/client/src/com/vaadin/client/ui/VOverlay.java
@@ -27,6 +27,7 @@ import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -689,4 +690,68 @@ public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
return container;
}
+ @Override
+ public void center() {
+ super.center();
+
+ // Some devices can be zoomed in, we should center to the visual
+ // viewport for those devices
+ BrowserInfo b = BrowserInfo.get();
+ if (b.isAndroid() || b.isIOS()) {
+ int left = (getVisualViewportWidth() - getOffsetWidth()) >> 1;
+ int top = (getVisualViewportHeight() - getOffsetHeight()) >> 1;
+ setPopupPosition(Math.max(Window.getScrollLeft() + left, 0),
+ Math.max(Window.getScrollTop() + top, 0));
+ }
+
+ }
+
+ /**
+ * Gets the visual viewport width, which is useful for e.g iOS where the
+ * view can be zoomed in while keeping the layout viewport intact.
+ *
+ * Falls back to layout viewport; for those browsers/devices the difference
+ * is that the scrollbar with is included (if there is a scrollbar).
+ *
+ * @since 7.0.7
+ * @return
+ */
+ private int getVisualViewportWidth() {
+ int w = (int) getSubpixelInnerWidth();
+ if (w < 0) {
+ return Window.getClientWidth();
+ } else {
+ return w;
+ }
+ }
+
+ /**
+ * Gets the visual viewport height, which is useful for e.g iOS where the
+ * view can be zoomed in while keeping the layout viewport intact.
+ *
+ * Falls back to layout viewport; for those browsers/devices the difference
+ * is that the scrollbar with is included (if there is a scrollbar).
+ *
+ * @since 7.0.7
+ * @return
+ */
+ private int getVisualViewportHeight() {
+ int h = (int) getSubpixelInnerHeight();
+ if (h < 0) {
+ return Window.getClientHeight();
+ } else {
+ return h;
+ }
+ }
+
+ private native double getSubpixelInnerWidth()
+ /*-{
+ return $wnd.innerWidth !== undefined ? $wnd.innerWidth : -1;
+ }-*/;
+
+ private native double getSubpixelInnerHeight()
+ /*-{
+ return $wnd.innerHeight !== undefined ? $wnd.innerHeight :-1;
+ }-*/;
+
}
diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java
index 8705a826cc..e2e82a1959 100644
--- a/client/src/com/vaadin/client/ui/VScrollTable.java
+++ b/client/src/com/vaadin/client/ui/VScrollTable.java
@@ -6692,6 +6692,17 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
private void setContainerHeight() {
if (!isDynamicHeight()) {
+
+ /*
+ * Android 2.3 cannot measure the height of the inline-block
+ * properly, and will return the wrong offset height. So for android
+ * 2.3 we set the element to a block element while measuring and
+ * then restore it which yields the correct result. #11331
+ */
+ if (BrowserInfo.get().isAndroid23()) {
+ getElement().getStyle().setDisplay(Display.BLOCK);
+ }
+
containerHeight = getOffsetHeight();
containerHeight -= showColHeaders ? tHead.getOffsetHeight() : 0;
containerHeight -= tFoot.getOffsetHeight();
@@ -6699,7 +6710,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
if (containerHeight < 0) {
containerHeight = 0;
}
+
scrollBodyPanel.setHeight(containerHeight + "px");
+
+ if (BrowserInfo.get().isAndroid23()) {
+ getElement().getStyle().clearDisplay();
+ }
}
}
diff --git a/client/src/com/vaadin/client/ui/VTextualDate.java b/client/src/com/vaadin/client/ui/VTextualDate.java
index 9307455a83..9d7e31faab 100644
--- a/client/src/com/vaadin/client/ui/VTextualDate.java
+++ b/client/src/com/vaadin/client/ui/VTextualDate.java
@@ -82,6 +82,9 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
getClient()
.updateVariable(getId(), EventId.FOCUS, "", true);
}
+
+ // Needed for tooltip event handling
+ VTextualDate.this.fireEvent(event);
}
});
text.addBlurHandler(new BlurHandler() {
@@ -100,6 +103,9 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
EventId.BLUR)) {
getClient().updateVariable(getId(), EventId.BLUR, "", true);
}
+
+ // Needed for tooltip event handling
+ VTextualDate.this.fireEvent(event);
}
});
diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java
index 079e133438..643d687f1d 100644
--- a/client/src/com/vaadin/client/ui/ui/UIConnector.java
+++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java
@@ -68,6 +68,7 @@ import com.vaadin.shared.ui.ComponentStateUtil;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;
import com.vaadin.shared.ui.ui.PageClientRpc;
+import com.vaadin.shared.ui.ui.PageState;
import com.vaadin.shared.ui.ui.ScrollClientRpc;
import com.vaadin.shared.ui.ui.UIClientRpc;
import com.vaadin.shared.ui.ui.UIConstants;
@@ -138,7 +139,7 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
getRpcProxy(UIServerRpc.class).resize(event.getHeight(),
event.getWidth(), Window.getClientWidth(),
Window.getClientHeight());
- if (getState().immediate) {
+ if (getState().immediate || getPageState().hasResizeListeners) {
getConnection().sendPendingVariableChanges();
}
}
@@ -504,6 +505,23 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
return (UIState) super.getState();
}
+ /**
+ * Returns the state of the Page associated with the UI.
+ * <p>
+ * Note that state is considered an internal part of the connector. You
+ * should not rely on the state object outside of the connector who owns it.
+ * If you depend on the state of other connectors you should use their
+ * public API instead of their state object directly. The page state might
+ * not be an independent state object but can be embedded in UI state.
+ * </p>
+ *
+ * @since 7.1
+ * @return state object of the page
+ */
+ public PageState getPageState() {
+ return getState().pageState;
+ }
+
@Override
public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
ComponentConnector oldChild = null;
@@ -611,6 +629,11 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
if (stateChangeEvent.hasPropertyChanged("pushMode")) {
getConnection().setPushEnabled(getState().pushMode.isEnabled());
}
+
+ if (stateChangeEvent.hasPropertyChanged("overlayContainerLabel")) {
+ getConnection().setOverlayContainerLabel(
+ getState().overlayContainerLabel);
+ }
}
private void configurePolling() {
diff --git a/scripts/automerge7.sh b/scripts/automerge7.sh
index 564296f5db..7b8c37a5aa 100755
--- a/scripts/automerge7.sh
+++ b/scripts/automerge7.sh
@@ -67,6 +67,14 @@ maybe_commit_and_push() {
pushMerged
}
+can_merge() {
+ commit=$1
+ git merge --no-commit --no-ff $commit > /dev/null 2>&1
+ result=$?
+ git reset --hard HEAD > /dev/null 2>&1
+ return $result
+}
+
nothingToCommit=`git status | grep "nothing to commit"`
if [ "$nothingToCommit" == "" ]
then
@@ -89,9 +97,21 @@ do
commitMsg=`git log -n 1 --format=oneline --abbrev-commit $commit`
if [ "$mergeDirective" == "" ]
then
- pendingCommit=$commit
- pendingCommitMessage=$pendingCommitMessage"$commitMsg\n"
- echo pendingCommitMessage: $pendingCommitMessage
+ if can_merge $commit
+ then
+ pendingCommit=$commit
+ pendingCommitMessage=$pendingCommitMessage"$commitMsg\n"
+ echo pendingCommitMessage: $pendingCommitMessage
+ else
+ maybe_commit_and_push $pendingCommit "$pendingCommitMessage"
+ pendingCommit=
+ pendingCommitMessage=
+ echo
+ echo "Stopping merge because $commit because of merge conflicts"
+ echo "The following commit must be manually merged."
+ show $commit
+ exit 3
+ fi
elif [ "$mergeDirective" == "no" ]
then
maybe_commit_and_push $pendingCommit "$pendingCommitMessage"
diff --git a/server/src/com/vaadin/server/Page.java b/server/src/com/vaadin/server/Page.java
index a7e0f7dcb3..d4c16fe7f7 100644
--- a/server/src/com/vaadin/server/Page.java
+++ b/server/src/com/vaadin/server/Page.java
@@ -30,7 +30,9 @@ import java.util.Map;
import com.vaadin.event.EventRouter;
import com.vaadin.shared.ui.BorderStyle;
import com.vaadin.shared.ui.ui.PageClientRpc;
+import com.vaadin.shared.ui.ui.PageState;
import com.vaadin.shared.ui.ui.UIConstants;
+import com.vaadin.shared.ui.ui.UIState;
import com.vaadin.ui.JavaScript;
import com.vaadin.ui.LegacyWindow;
import com.vaadin.ui.Link;
@@ -220,7 +222,7 @@ public class Page implements Serializable {
}
}
- private static final Method BROWSWER_RESIZE_METHOD = ReflectTools
+ private static final Method BROWSER_RESIZE_METHOD = ReflectTools
.findMethod(BrowserWindowResizeListener.class,
"browserWindowResized", BrowserWindowResizeEvent.class);
@@ -417,8 +419,11 @@ public class Page implements Serializable {
*/
private URI location;
- public Page(UI uI) {
+ private final PageState state;
+
+ public Page(UI uI, PageState state) {
this.uI = uI;
+ this.state = state;
}
private void addListener(Class<?> eventType, Object target, Method method) {
@@ -604,20 +609,27 @@ public class Page implements Serializable {
}
/**
- * Adds a new {@link BrowserWindowResizeListener} to this uI. The listener
- * will be notified whenever the browser window within which this uI resides
+ * Adds a new {@link BrowserWindowResizeListener} to this UI. The listener
+ * will be notified whenever the browser window within which this UI resides
* is resized.
+ * <p>
+ * In most cases, the UI should be in lazy resize mode when using browser
+ * window resize listeners. Otherwise, a large number of events can be
+ * received while a resize is being performed. Use
+ * {@link UI#setResizeLazy(boolean)}.
+ * </p>
*
* @param resizeListener
* the listener to add
*
* @see BrowserWindowResizeListener#browserWindowResized(BrowserWindowResizeEvent)
- * @see #setResizeLazy(boolean)
+ * @see UI#setResizeLazy(boolean)
*/
public void addBrowserWindowResizeListener(
BrowserWindowResizeListener resizeListener) {
addListener(BrowserWindowResizeEvent.class, resizeListener,
- BROWSWER_RESIZE_METHOD);
+ BROWSER_RESIZE_METHOD);
+ getState(true).hasResizeListeners = true;
}
/**
@@ -639,7 +651,9 @@ public class Page implements Serializable {
public void removeBrowserWindowResizeListener(
BrowserWindowResizeListener resizeListener) {
removeListener(BrowserWindowResizeEvent.class, resizeListener,
- BROWSWER_RESIZE_METHOD);
+ BROWSER_RESIZE_METHOD);
+ getState(true).hasResizeListeners = eventRouter
+ .hasListeners(BrowserWindowResizeEvent.class);
}
/**
@@ -1038,4 +1052,29 @@ public class Page implements Serializable {
uI.getRpcProxy(PageClientRpc.class).reload();
}
+ /**
+ * Returns the page state.
+ * <p>
+ * The page state is transmitted to UIConnector together with
+ * {@link UIState} rather than as an individual entity.
+ * </p>
+ * <p>
+ * The state should be considered an internal detail of Page. Classes
+ * outside of Page should not access it directly but only through public
+ * APIs provided by Page.
+ * </p>
+ *
+ * @since 7.1
+ * @param markAsDirty
+ * true to mark the state as dirty
+ * @return PageState object that can be read in any case and modified if
+ * markAsDirty is true
+ */
+ protected PageState getState(boolean markAsDirty) {
+ if (markAsDirty) {
+ uI.markAsDirty();
+ }
+ return state;
+ }
+
}
diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java
index 6648f69ff9..3bca63a3b7 100644
--- a/server/src/com/vaadin/ui/AbstractField.java
+++ b/server/src/com/vaadin/ui/AbstractField.java
@@ -323,7 +323,7 @@ public abstract class AbstractField<T> extends AbstractComponent implements
*/
@Override
public boolean isModified() {
- return getState().modified;
+ return getState(false).modified;
}
private void setModified(boolean modified) {
@@ -1276,7 +1276,7 @@ public abstract class AbstractField<T> extends AbstractComponent implements
*/
@Override
public int getTabIndex() {
- return getState().tabIndex;
+ return getState(false).tabIndex;
}
/*
@@ -1408,7 +1408,7 @@ public abstract class AbstractField<T> extends AbstractComponent implements
*/
@Override
public boolean isRequired() {
- return getState().required;
+ return getState(false).required;
}
/**
@@ -1663,6 +1663,11 @@ public abstract class AbstractField<T> extends AbstractComponent implements
}
@Override
+ protected AbstractFieldState getState(boolean markAsDirty) {
+ return (AbstractFieldState) super.getState(markAsDirty);
+ }
+
+ @Override
public void beforeClientResponse(boolean initial) {
super.beforeClientResponse(initial);
diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java
index 3574c5527d..0a4ed7c491 100644
--- a/server/src/com/vaadin/ui/UI.java
+++ b/server/src/com/vaadin/ui/UI.java
@@ -117,7 +117,7 @@ public abstract class UI extends AbstractSingleComponentContainer implements
/** Identifies the click event */
private ConnectorTracker connectorTracker = new ConnectorTracker(this);
- private Page page = new Page(this);
+ private Page page = new Page(this, getState(false).pageState);
private LoadingIndicatorConfiguration loadingIndicatorConfiguration = new LoadingIndicatorConfigurationImpl(
this);
@@ -686,10 +686,16 @@ public abstract class UI extends AbstractSingleComponentContainer implements
/**
* Should resize operations be lazy, i.e. should there be a delay before
- * layout sizes are recalculated. Speeds up resize operations in slow UIs
- * with the penalty of slightly decreased usability.
+ * layout sizes are recalculated and resize events are sent to the server.
+ * Speeds up resize operations in slow UIs with the penalty of slightly
+ * decreased usability.
* <p>
* Default value: <code>false</code>
+ * </p>
+ * <p>
+ * When there are active window resize listeners, lazy resize mode should be
+ * used to avoid a large number of events during resize.
+ * </p>
*
* @param resizeLazy
* true to use a delay before recalculating sizes, false to
@@ -1327,4 +1333,28 @@ public abstract class UI extends AbstractSingleComponentContainer implements
getState().pushMode = pushMode;
}
+ /**
+ * Get the label that is added to the container element, where tooltip,
+ * notification and dialogs are added to.
+ *
+ * @return the label of the container
+ */
+ public String getOverlayContainerLabel() {
+ return getState().overlayContainerLabel;
+ }
+
+ /**
+ * Sets the label that is added to the container element, where tooltip,
+ * notifications and dialogs are added to.
+ * <p>
+ * This is helpful for users of assistive devices, as this element is
+ * reachable for them.
+ * </p>
+ *
+ * @param overlayContainerLabel
+ * label to use for the container
+ */
+ public void setOverlayContainerLabel(String overlayContainerLabel) {
+ getState().overlayContainerLabel = overlayContainerLabel;
+ }
}
diff --git a/server/tests/src/com/vaadin/server/VaadinSessionTest.java b/server/tests/src/com/vaadin/server/VaadinSessionTest.java
index 8f471afd46..61a1581a6f 100644
--- a/server/tests/src/com/vaadin/server/VaadinSessionTest.java
+++ b/server/tests/src/com/vaadin/server/VaadinSessionTest.java
@@ -74,7 +74,7 @@ public class VaadinSessionTest {
session.storeInSession(mockService, mockWrappedSession);
ui = new UI() {
- Page page = new Page(this) {
+ Page page = new Page(this, getState(false).pageState) {
@Override
public void init(VaadinRequest request) {
}
diff --git a/shared/src/com/vaadin/shared/ui/ui/PageState.java b/shared/src/com/vaadin/shared/ui/ui/PageState.java
new file mode 100644
index 0000000000..0b51eb4bba
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/ui/PageState.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/**
+ * The shared state of a {@link com.vaadin.server.Page Page}.
+ *
+ * Note that at the moment this is not a stand-alone state class but embedded in
+ * {@link UIState}. This might change in the future.
+ *
+ * @since 7.1
+ */
+public class PageState implements Serializable {
+ /**
+ * True if the page has browser window resize listeners.
+ */
+ public boolean hasResizeListeners = false;
+} \ No newline at end of file
diff --git a/shared/src/com/vaadin/shared/ui/ui/UIState.java b/shared/src/com/vaadin/shared/ui/ui/UIState.java
index e8be9d674c..16c1ed16c7 100644
--- a/shared/src/com/vaadin/shared/ui/ui/UIState.java
+++ b/shared/src/com/vaadin/shared/ui/ui/UIState.java
@@ -27,6 +27,10 @@ public class UIState extends TabIndexState {
public PushMode pushMode = PushMode.DISABLED;
+ // Informing users of assistive devices, that the content of this container
+ // is announced automatically and does not need to be navigated into
+ public String overlayContainerLabel = "This content is announced automatically and does not need to be navigated into.";
+
public static class LoadingIndicatorConfigurationState implements
Serializable {
public int firstDelay = 300;
@@ -42,9 +46,14 @@ public class UIState extends TabIndexState {
public int maxWidth = 500;
}
+ /**
+ * State related to the {@link Page} class.
+ */
+ public PageState pageState = new PageState();
+
{
primaryStyleName = "v-ui";
// Default is 1 for legacy reasons
tabIndex = 1;
}
-} \ No newline at end of file
+}
diff --git a/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutWithNonIntegerWidth.java b/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutWithNonIntegerWidth.java
new file mode 100644
index 0000000000..8312b15ba7
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/gridlayout/GridLayoutWithNonIntegerWidth.java
@@ -0,0 +1,53 @@
+package com.vaadin.tests.components.gridlayout;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ * Main UI class
+ */
+@SuppressWarnings("serial")
+public class GridLayoutWithNonIntegerWidth extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ Panel p1 = new Panel("Panel with GridLayout");
+ GridLayout grid = new GridLayout(1, 1, new Label("A"));
+ grid.setWidth(100, Unit.PERCENTAGE);
+ p1.setContent(grid);
+ p1.setWidth("354.390625px");
+
+ Panel p2 = new Panel("Panel with HorizontalLayout");
+ HorizontalLayout hl = new HorizontalLayout(new Label("A"));
+ hl.setWidth(100, Unit.PERCENTAGE);
+ p2.setContent(hl);
+ p2.setWidth("354.390625px");
+
+ setContent(new VerticalLayout(p1, p2));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription()
+ */
+ @Override
+ protected String getTestDescription() {
+ return "Neither of the panels should contain scrollbars";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber()
+ */
+ @Override
+ protected Integer getTicketNumber() {
+ return 11775;
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.html b/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.html
index c1734481c6..e41cf5e176 100644
--- a/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.html
+++ b/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.html
@@ -55,6 +55,11 @@
</tr>
<tr>
<td>mouseMoveAt</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>mouseMoveAt</td>
<td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SshortTooltip</td>
<td>0,0</td>
</tr>
@@ -117,6 +122,11 @@
</tr>
<tr>
<td>mouseMoveAt</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>mouseMoveAt</td>
<td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SlongTooltip</td>
<td>0,0</td>
</tr>
diff --git a/uitest/src/com/vaadin/tests/components/window/CenteredInVisualViewport.java b/uitest/src/com/vaadin/tests/components/window/CenteredInVisualViewport.java
new file mode 100644
index 0000000000..428b2ae3f9
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/CenteredInVisualViewport.java
@@ -0,0 +1,66 @@
+package com.vaadin.tests.components.window;
+
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Window;
+
+public class CenteredInVisualViewport extends TestBase {
+
+ @Override
+ protected String getDescription() {
+ return "Should open centered, even if zoomed in on one button (e.g zoom in iOS)";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 11614;
+ }
+
+ @Override
+ protected void setup() {
+ GridLayout layout = new GridLayout(3, 3);
+ layout.setWidth("1000px");
+ layout.setHeight("1000px");
+ addComponent(layout);
+
+ Button b = new Button("Open", new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Window centered = new Window("A window", new Label(
+ "Centered window"));
+ centered.center();
+ getMainWindow().addWindow(centered);
+ }
+ });
+ layout.addComponent(b, 0, 0);
+
+ b = new Button("Open", new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Window centered = new Window("A window", new Label(
+ "Centered window"));
+ centered.center();
+ getMainWindow().addWindow(centered);
+ }
+ });
+ layout.addComponent(b, 1, 1);
+
+ b = new Button("Open", new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Window centered = new Window("A window", new Label(
+ "Centered window"));
+ centered.center();
+ getMainWindow().addWindow(centered);
+ }
+ });
+ layout.addComponent(b, 2, 2);
+
+ }
+}