summaryrefslogtreecommitdiffstats
path: root/client/src
diff options
context:
space:
mode:
authorArtur Signell <artur@vaadin.com>2016-04-17 11:31:01 +0300
committerVaadin Code Review <review@vaadin.com>2016-04-28 15:18:45 +0000
commit0b0495b6d87b3c623b38643ff1ce27abf5a30d5c (patch)
treed0c0b29753148eac0b7c1d473d10bf8d1235ed99 /client/src
parentab30dfe29d12e57d7c00c12cf2edc9328cb47a65 (diff)
downloadvaadin-framework-0b0495b6d87b3c623b38643ff1ce27abf5a30d5c.tar.gz
vaadin-framework-0b0495b6d87b3c623b38643ff1ce27abf5a30d5c.zip
Restrict grid sidebar size to visible viewport (#19349)
Change-Id: I75b7c662251de53b46e045d17d3cac650586acd2
Diffstat (limited to 'client/src')
-rw-r--r--client/src/main/java/com/vaadin/client/widgets/Grid.java1
-rw-r--r--client/src/main/java/com/vaadin/client/widgets/Overlay.java137
2 files changed, 134 insertions, 4 deletions
diff --git a/client/src/main/java/com/vaadin/client/widgets/Grid.java b/client/src/main/java/com/vaadin/client/widgets/Grid.java
index cf9456d8a8..c388dbc951 100644
--- a/client/src/main/java/com/vaadin/client/widgets/Grid.java
+++ b/client/src/main/java/com/vaadin/client/widgets/Grid.java
@@ -3760,6 +3760,7 @@ public class Grid<T> extends ResizeComposite implements
addStyleName("closed");
}
});
+ overlay.setFitInWindow(true);
}
/**
diff --git a/client/src/main/java/com/vaadin/client/widgets/Overlay.java b/client/src/main/java/com/vaadin/client/widgets/Overlay.java
index a5e29c6774..6744840c8e 100644
--- a/client/src/main/java/com/vaadin/client/widgets/Overlay.java
+++ b/client/src/main/java/com/vaadin/client/widgets/Overlay.java
@@ -16,6 +16,9 @@
package com.vaadin.client.widgets;
+import java.util.ArrayList;
+import java.util.List;
+
import com.google.gwt.animation.client.Animation;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
@@ -29,6 +32,7 @@ import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.PopupPanel;
@@ -238,6 +242,8 @@ public class Overlay extends PopupPanel implements CloseHandler<PopupPanel> {
@Deprecated
private boolean sinkShadowEvents = false;
+ private List<Command> runOnClose = new ArrayList<Command>();
+
public Overlay() {
super();
adjustZIndex();
@@ -362,6 +368,58 @@ public class Overlay extends PopupPanel implements CloseHandler<PopupPanel> {
@Override
public void setPopupPosition(int left, int top) {
+
+ // PopupPanel tries to position the popup on screen (by
+ // default right, below) and will move it if there is not
+ // enough space right or below but only if there is
+ // sufficient space left or above. If the popup is too big
+ // to fit on either side, it will be in the original
+ // position.
+
+ if (isFitInWindow()) {
+ int windowLeft = Window.getScrollLeft();
+ int windowRight = Window.getScrollLeft() + Window.getClientWidth();
+ int width = getOffsetWidth();
+ int popupRight = left + width;
+ int popupRightOfWindow = popupRight - windowRight;
+ if (popupRightOfWindow > 0) {
+ // Popup is too large to fit
+ left -= popupRightOfWindow;
+ if (left < 0) {
+ // Would move left of screen, shrink to fit in window
+ setOuterWidthThroughWidget(windowRight - windowLeft);
+ runOnClose.add(new Command() {
+ @Override
+ public void execute() {
+ getWidget().setWidth("");
+ }
+ });
+ left = 0;
+ }
+ }
+
+ int windowTop = Window.getScrollTop();
+ int windowBottom = Window.getScrollTop() + Window.getClientHeight();
+ int height = getOffsetHeight();
+ int popupBottom = top + height;
+ int popupBelowWindow = popupBottom - windowBottom;
+ if (popupBelowWindow > 0) {
+ // Popup is too large to fit
+ top -= popupBelowWindow;
+ if (top < 0) {
+ // Would move above screen, shrink to fit in window
+ setOuterHeightThroughWidget(windowBottom - windowTop);
+ runOnClose.add(new Command() {
+ @Override
+ public void execute() {
+ getWidget().setHeight("");
+ }
+ });
+ top = 0;
+ }
+ }
+ }
+
// TODO, this should in fact be part of
// Document.get().getBodyOffsetLeft/Top(). Would require overriding DOM
// for all permutations. Now adding fix as margin instead of fixing
@@ -373,6 +431,30 @@ public class Overlay extends PopupPanel implements CloseHandler<PopupPanel> {
positionOrSizeUpdated(isAnimationEnabled() ? 0 : 1);
}
+ private void setOuterHeightThroughWidget(int outerHeight) {
+ getWidget().setHeight(outerHeight + "px");
+
+ // Take margin/border/padding into account if needed
+ // (the height is for the overlay root but we set it on the
+ // widget)
+ int adjustedHeight = outerHeight - (getOffsetHeight() - outerHeight);
+ if (adjustedHeight != outerHeight) {
+ getWidget().setHeight(adjustedHeight + "px");
+ }
+ }
+
+ private void setOuterWidthThroughWidget(int outerWidth) {
+ getWidget().setWidth(outerWidth + "px");
+
+ // Take margin/border/padding into account if needed
+ // (the height is for the overlay root but we set it on the
+ // widget)
+ int adjustedWidth = outerWidth - (getOffsetWidth() - outerWidth);
+ if (adjustedWidth != outerWidth) {
+ getWidget().setWidth(adjustedWidth + "px");
+ }
+ }
+
private IFrameElement getShimElement() {
if (shimElement == null && needsShimElement()) {
shimElement = Document.get().createIFrameElement();
@@ -465,6 +547,8 @@ public class Overlay extends PopupPanel implements CloseHandler<PopupPanel> {
private JavaScriptObject animateInListener;
+ private boolean fitInWindow = false;
+
private boolean maybeShowWithAnimation() {
boolean isAttached = isAttached() && isShowing();
super.show();
@@ -933,7 +1017,7 @@ public class Overlay extends PopupPanel implements CloseHandler<PopupPanel> {
public void hide(final boolean autoClosed, final boolean animateIn,
final boolean animateOut) {
if (BrowserInfo.get().isIE8() || BrowserInfo.get().isIE9()) {
- super.hide(autoClosed);
+ reallyHide(autoClosed);
} else {
if (animateIn
&& getStyleName().contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) {
@@ -945,7 +1029,7 @@ public class Overlay extends PopupPanel implements CloseHandler<PopupPanel> {
.getAnimationName(event)
.contains(
ADDITIONAL_CLASSNAME_ANIMATE_IN)) {
- Overlay.this.hide(autoClosed);
+ reallyHide(autoClosed);
}
}
});
@@ -990,7 +1074,7 @@ public class Overlay extends PopupPanel implements CloseHandler<PopupPanel> {
+ "-"
+ ADDITIONAL_CLASSNAME_ANIMATE_OUT);
}
- Overlay.super.hide(autoClosed);
+ reallyHide(autoClosed);
}
}
});
@@ -1003,10 +1087,55 @@ public class Overlay extends PopupPanel implements CloseHandler<PopupPanel> {
shadow.removeClassName(CLASSNAME_SHADOW + "-"
+ ADDITIONAL_CLASSNAME_ANIMATE_OUT);
}
- super.hide(autoClosed);
+ reallyHide(autoClosed);
}
}
}
}
+ private void reallyHide(boolean autoClosed) {
+ super.hide(autoClosed);
+ for (Command c : runOnClose) {
+ c.execute();
+ }
+ runOnClose.clear();
+ }
+
+ /**
+ * Sets whether the overlay should be moved or shrunk to fit inside the
+ * window.
+ * <p>
+ * When this is <code>false</code>, the default {@link PopupPanel} behavior
+ * is used, which tries to position the popup primarly below and to the
+ * right of a reference UIObject and, if there is not enough space, above or
+ * to the left.
+ * <p>
+ * When this is <code>true</code>, the popup will be moved up/left in case
+ * it does not fit on either side. If the popup is larger than the window,
+ * it will be shrunk to fit and assume that scrolling e.g. using
+ * <code>overflow:auto</code>, is taken care of by the overlay user.
+ *
+ * @since
+ * @param fitInWindow
+ * <code>true</code> to ensure that no part of the popup is
+ * outside the visible view, <code>false</code> to use the
+ * default {@link PopupPanel} behavior
+ */
+ public void setFitInWindow(boolean fitInWindow) {
+ this.fitInWindow = fitInWindow;
+ }
+
+ /**
+ * Checks whether the overlay should be moved or shrunk to fit inside the
+ * window.
+ *
+ * @see #setFitInWindow(boolean)
+ *
+ * @since
+ * @return <code>true</code> if the popup will be moved and/or shrunk to fit
+ * inside the window, <code>false</code> otherwise
+ */
+ public boolean isFitInWindow() {
+ return fitInWindow;
+ }
}