123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116 |
- /*
- * Copyright 2000-2014 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
- package com.vaadin.client.ui;
-
- import java.util.logging.Level;
- import java.util.logging.Logger;
-
- import com.google.gwt.animation.client.Animation;
- import com.google.gwt.aria.client.Roles;
- import com.google.gwt.core.client.JavaScriptObject;
- import com.google.gwt.core.client.Scheduler;
- import com.google.gwt.core.client.Scheduler.ScheduledCommand;
- import com.google.gwt.dom.client.Document;
- import com.google.gwt.dom.client.Element;
- import com.google.gwt.dom.client.IFrameElement;
- import com.google.gwt.dom.client.NativeEvent;
- import com.google.gwt.dom.client.Style;
- import com.google.gwt.dom.client.Style.BorderStyle;
- 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.DOM;
- 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;
- import com.vaadin.client.AnimationUtil;
- import com.vaadin.client.AnimationUtil.AnimationEndListener;
- import com.vaadin.client.ApplicationConnection;
- import com.vaadin.client.BrowserInfo;
- import com.vaadin.client.ComponentConnector;
- import com.vaadin.client.ComputedStyle;
- import com.vaadin.client.Util;
- import com.vaadin.client.WidgetUtil;
-
- /**
- * <p>
- * In Vaadin UI this Overlay should always be used for all elements that
- * temporary float over other components like context menus etc. This is to deal
- * stacking order correctly with VWindow objects.
- * </p>
- *
- * <h3>Shadow</h3>
- * <p>
- * The separate shadow element underneath the main overlay element is <strong>
- * <em>deprecated</em></strong>, and should not be used for new overlay
- * components. CSS box-shadow should be used instead of a separate shadow
- * element. Remember to include any vendor-prefixed versions to support all
- * browsers that you need to. To cover all possible browsers that Vaadin 7
- * supports, add <code>-webkit-box-shadow</code> and the standard
- * <code>box-shadow</code> properties.
- * </p>
- *
- * <p>
- * For IE8, which doesn't support CSS box-shadow, you can use the proprietary
- * DropShadow filter. It doesn't provide the exact same features as box-shadow,
- * but it is suitable for graceful degradation. Other options are to use a
- * border or a pseudo-element underneath the overlay which mimics a shadow, or
- * any combination of these.
- * </p>
- *
- * <p>
- * Read more about the DropShadow filter from <a
- * href="http://msdn.microsoft.com/en-us/library/ms532985(v=vs.85).aspx"
- * >Microsoft Developer Network</a>
- * </p>
- */
- public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
-
- @Override
- protected void onAttach() {
- // Move the overlay to the appropriate overlay container
- final VOverlay overlay = VOverlay.current;
- if (overlay != null) {
- final Element e = overlay.getOverlayContainer();
- e.appendChild(getElement());
- }
-
- super.onAttach();
- }
-
- public static class PositionAndSize {
- private int left, top, width, height;
-
- public PositionAndSize(int left, int top, int width, int height) {
- super();
- setLeft(left);
- setTop(top);
- setWidth(width);
- setHeight(height);
- }
-
- public int getLeft() {
- return left;
- }
-
- public void setLeft(int left) {
- this.left = left;
- }
-
- public int getTop() {
- return top;
- }
-
- public void setTop(int top) {
- this.top = top;
- }
-
- public int getWidth() {
- return width;
- }
-
- public void setWidth(int width) {
- if (width < 0) {
- width = 0;
- }
-
- this.width = width;
- }
-
- public int getHeight() {
- return height;
- }
-
- public void setHeight(int height) {
- if (height < 0) {
- height = 0;
- }
-
- this.height = height;
- }
-
- public void setAnimationFromCenterProgress(double progress) {
- left += (int) (width * (1.0 - progress) / 2.0);
- top += (int) (height * (1.0 - progress) / 2.0);
- width = (int) (width * progress);
- height = (int) (height * progress);
- }
- }
-
- /*
- * The z-index value from where all overlays live. This can be overridden in
- * any extending class.
- */
- public static int Z_INDEX = 20000;
-
- private static int leftFix = -1;
-
- private static int topFix = -1;
-
- /**
- * Shadow element style. If an extending class wishes to use a different
- * style of shadow, it can use setShadowStyle(String) to give the shadow
- * element a new style name.
- *
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- public static final String CLASSNAME_SHADOW = "v-shadow";
-
- /**
- * Style name for the overlay container element (see
- * {@link #getOverlayContainer()}
- */
- public static final String CLASSNAME_CONTAINER = "v-overlay-container";
-
- /**
- * @since 7.3
- */
- public static final String ADDITIONAL_CLASSNAME_ANIMATE_IN = "animate-in";
- /**
- * @since 7.3
- */
- public static final String ADDITIONAL_CLASSNAME_ANIMATE_OUT = "animate-out";
-
- /**
- * The shadow element for this overlay.
- *
- * @deprecated See main JavaDoc for VOverlay
- *
- */
- @Deprecated
- private Element shadow;
-
- /*
- * The creator of this VOverlay (the widget that made the instance, not the
- * layout parent)
- */
- private Widget owner;
-
- /*
- * ApplicationConnection that this overlay belongs to, which is needed to
- * create the overlay in the correct container so that the correct styles
- * are applied. If not given, owner will be used to figure out, and as a
- * last fallback, the overlay is created w/o container, potentially missing
- * styles.
- */
- protected ApplicationConnection ac;
-
- /**
- * The shim iframe behind the overlay, allowing PDFs and applets to be
- * covered by overlays.
- */
- private IFrameElement shimElement;
-
- /**
- * The HTML snippet that is used to render the actual shadow. In consists of
- * nine different DIV-elements with the following class names:
- *
- * <pre>
- * .v-shadow[-stylename]
- * ----------------------------------------------
- * | .top-left | .top | .top-right |
- * |---------------|-----------|----------------|
- * | | | |
- * | .left | .center | .right |
- * | | | |
- * |---------------|-----------|----------------|
- * | .bottom-left | .bottom | .bottom-right |
- * ----------------------------------------------
- * </pre>
- *
- * See default theme 'shadow.css' for implementation example.
- *
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- 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
- */
- private static final int POPUP_PANEL_ANIMATION_DURATION = 200;
-
- /**
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- private boolean sinkShadowEvents = false;
-
- public VOverlay() {
- super();
- adjustZIndex();
- }
-
- public VOverlay(boolean autoHide) {
- super(autoHide);
- adjustZIndex();
- }
-
- public VOverlay(boolean autoHide, boolean modal) {
- super(autoHide, modal);
- adjustZIndex();
- }
-
- /**
- * @deprecated See main JavaDoc for VOverlay. Use the other constructors
- * without the <code>showShadow</code> parameter.
- */
- @Deprecated
- public VOverlay(boolean autoHide, boolean modal, boolean showShadow) {
- super(autoHide, modal);
- setShadowEnabled(showShadow && useShadowDiv());
- adjustZIndex();
- }
-
- /**
- * Return true if a separate shadow div should be used. Since Vaadin 7.3,
- * shadows are implemented with CSS box-shadow. Thus, a shadow div is only
- * used for IE8 by default.
- *
- * @deprecated See main JavaDoc for VOverlay
- * @since 7.3
- * @return true to use a shadow div
- */
- @Deprecated
- protected boolean useShadowDiv() {
- return BrowserInfo.get().isIE8();
- }
-
- /**
- * Method to control whether DOM elements for shadow are added. With this
- * method subclasses can control displaying of shadow also after the
- * constructor.
- *
- * @param enabled
- * true if shadow should be displayed
- *
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- protected void setShadowEnabled(boolean enabled) {
- if (enabled != isShadowEnabled()) {
- if (enabled) {
- shadow = DOM.createDiv();
- shadow.setClassName(CLASSNAME_SHADOW);
- shadow.setInnerHTML(SHADOW_HTML);
- shadow.getStyle().setPosition(Position.ABSOLUTE);
- addCloseHandler(this);
- } else {
- removeShadowIfPresent();
- shadow = null;
- }
- }
- }
-
- /**
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- protected boolean isShadowEnabled() {
- return shadow != null;
- }
-
- protected boolean isShimElementEnabled() {
- return shimElement != null;
- }
-
- private void removeShimElement() {
- if (shimElement != null) {
- shimElement.removeFromParent();
- }
- }
-
- /**
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- private void removeShadowIfPresent() {
- if (isShadowAttached()) {
- // Remove event listener from the shadow
- unsinkShadowEvents();
-
- shadow.removeFromParent();
- }
- }
-
- /**
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- private boolean isShadowAttached() {
- return isShadowEnabled() && shadow.getParentElement() != null;
- }
-
- private void adjustZIndex() {
- setZIndex(Z_INDEX);
- }
-
- /**
- * Set the z-index (visual stack position) for this overlay.
- *
- * @param zIndex
- * The new z-index
- */
- protected void setZIndex(int zIndex) {
- getElement().getStyle().setZIndex(zIndex);
- if (isShadowEnabled()) {
- shadow.getStyle().setZIndex(zIndex);
- }
- }
-
- @Override
- public void setPopupPosition(int left, int top) {
- // 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
- // left/top because parent class saves the position.
- Style style = getElement().getStyle();
- style.setMarginLeft(-adjustByRelativeLeftBodyMargin(), Unit.PX);
- style.setMarginTop(-adjustByRelativeTopBodyMargin(), Unit.PX);
- super.setPopupPosition(left, top);
- positionOrSizeUpdated(isAnimationEnabled() ? 0 : 1);
- }
-
- private IFrameElement getShimElement() {
- if (shimElement == null && needsShimElement()) {
- shimElement = Document.get().createIFrameElement();
-
- // Insert shim iframe before the main overlay element. It does not
- // matter if it is in front or behind the shadow as we cannot put a
- // shim behind the shadow due to its transparency.
- shimElement.getStyle().setPosition(Position.ABSOLUTE);
- shimElement.getStyle().setBorderStyle(BorderStyle.NONE);
- shimElement.setTabIndex(-1);
- shimElement.setFrameBorder(0);
- shimElement.setMarginHeight(0);
- }
- return shimElement;
- }
-
- private int getActualTop() {
- int y = getAbsoluteTop();
-
- /* This is needed for IE7 at least */
- // Account for the difference between absolute position and the
- // body's positioning context.
- y -= Document.get().getBodyOffsetTop();
- y -= adjustByRelativeTopBodyMargin();
-
- return y;
- }
-
- private int getActualLeft() {
- int x = getAbsoluteLeft();
-
- /* This is needed for IE7 at least */
- // Account for the difference between absolute position and the
- // body's positioning context.
- x -= Document.get().getBodyOffsetLeft();
- x -= adjustByRelativeLeftBodyMargin();
-
- return x;
- }
-
- private static int adjustByRelativeTopBodyMargin() {
- if (topFix == -1) {
- topFix = detectRelativeBodyFixes("top");
- }
- return topFix;
- }
-
- private native static int detectRelativeBodyFixes(String axis)
- /*-{
- try {
- var b = $wnd.document.body;
- var cstyle = b.currentStyle ? b.currentStyle : getComputedStyle(b);
- if(cstyle && cstyle.position == 'relative') {
- return b.getBoundingClientRect()[axis];
- }
- } catch(e){}
- return 0;
- }-*/;
-
- private static int adjustByRelativeLeftBodyMargin() {
- if (leftFix == -1) {
- leftFix = detectRelativeBodyFixes("left");
-
- }
- return leftFix;
- }
-
- /*
- * A "thread local" of sorts, set temporarily so that VOverlayImpl knows
- * which VOverlay is using it, so that it can be attached to the correct
- * overlay container.
- *
- * TODO this is a strange pattern that we should get rid of when possible.
- */
- protected static VOverlay current;
-
- @Override
- public void show() {
- current = this;
-
- maybeShowWithAnimation();
-
- if (isAnimationEnabled()) {
- new ResizeAnimation().run(POPUP_PANEL_ANIMATION_DURATION);
- } else {
- if (BrowserInfo.get().isIE8()) {
- Scheduler.get().scheduleFinally(new ScheduledCommand() {
-
- @Override
- public void execute() {
- positionOrSizeUpdated(1.0);
- }
- });
- } else {
- positionOrSizeUpdated(1.0);
- }
- }
- current = null;
- }
-
- private JavaScriptObject animateInListener;
-
- private boolean maybeShowWithAnimation() {
- boolean isAttached = isAttached() && isShowing();
- super.show();
-
- // Don't animate if already visible or browser is IE8 or IE9 (no CSS
- // animation support)
- if (isAttached || BrowserInfo.get().isIE8()
- || BrowserInfo.get().isIE9()) {
- return false;
- } else {
- // Check if animations are used
- setVisible(false);
- addStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN);
- if (isShadowEnabled()) {
- shadow.addClassName(CLASSNAME_SHADOW + "-"
- + ADDITIONAL_CLASSNAME_ANIMATE_IN);
- }
-
- ComputedStyle cs = new ComputedStyle(getElement());
- String animationName = AnimationUtil.getAnimationName(cs);
- if (animationName == null) {
- animationName = "";
- }
- setVisible(true);
-
- if (animationName.contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) {
- // Disable GWT PopupPanel animation if used
- setAnimationEnabled(false);
- animateInListener = AnimationUtil.addAnimationEndListener(
- getElement(), new AnimationEndListener() {
- @Override
- public void onAnimationEnd(NativeEvent event) {
- String animationName = AnimationUtil
- .getAnimationName(event);
- if (animationName
- .contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) {
- AnimationUtil.removeAnimationEndListener(
- getElement(), animateInListener);
- removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN);
- if (isShadowEnabled()) {
- shadow.removeClassName(CLASSNAME_SHADOW
- + "-"
- + ADDITIONAL_CLASSNAME_ANIMATE_IN);
- }
- }
- }
- });
- return true;
- } else {
- removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN);
- if (isShadowEnabled()) {
- shadow.removeClassName(CLASSNAME_SHADOW + "-"
- + ADDITIONAL_CLASSNAME_ANIMATE_IN);
- }
- return false;
- }
- }
- }
-
- @Override
- protected void onDetach() {
- super.onDetach();
-
- // Always ensure shadow is removed when the overlay is removed.
- removeShadowIfPresent();
- removeShimElement();
- }
-
- @Override
- public void setVisible(boolean visible) {
- super.setVisible(visible);
- if (isShadowEnabled()) {
- shadow.getStyle().setProperty("visibility",
- visible ? "visible" : "hidden");
- }
- if (isShimElementEnabled()) {
- shimElement.getStyle().setProperty("visibility",
- visible ? "visible" : "hidden");
- }
- }
-
- @Override
- public void setWidth(String width) {
- super.setWidth(width);
- positionOrSizeUpdated(1.0);
- }
-
- @Override
- public void setHeight(String height) {
- super.setHeight(height);
- positionOrSizeUpdated(1.0);
- }
-
- /**
- * Sets the shadow style for this overlay. Will override any previous style
- * for the shadow. The default style name is defined by CLASSNAME_SHADOW.
- * The given style will be prefixed with CLASSNAME_SHADOW.
- *
- * @param style
- * The new style name for the shadow element. Will be prefixed by
- * CLASSNAME_SHADOW, e.g. style=='foobar' -> actual style
- * name=='v-shadow-foobar'.
- *
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- protected void setShadowStyle(String style) {
- if (isShadowEnabled()) {
- shadow.setClassName(CLASSNAME_SHADOW + "-" + style);
- }
- }
-
- /**
- * Extending classes should always call this method after they change the
- * size of overlay without using normal 'setWidth(String)' and
- * 'setHeight(String)' methods (if not calling super.setWidth/Height).
- *
- */
- public void positionOrSizeUpdated() {
- positionOrSizeUpdated(1.0);
- }
-
- /**
- * @deprecated Call {@link #positionOrSizeUpdated()} instead.
- */
- @Deprecated
- protected void updateShadowSizeAndPosition() {
- positionOrSizeUpdated();
- }
-
- /**
- * Recalculates proper position and dimensions for the shadow and shim
- * elements. Can be used to animate the related elements, using the
- * 'progress' parameter (used to animate the shadow in sync with GWT
- * PopupPanel's default animation 'PopupPanel.AnimationType.CENTER').
- *
- * @param progress
- * A value between 0.0 and 1.0, indicating the progress of the
- * animation (0=start, 1=end).
- */
- private void positionOrSizeUpdated(final double progress) {
- // Don't do anything if overlay element is not attached
- if (!isAttached()) {
- return;
- }
- // Calculate proper z-index
- int zIndex = -1;
- try {
- // Odd behaviour with Windows Hosted Mode forces us to use
- // this redundant try/catch block (See dev.vaadin.com #2011)
- zIndex = Integer.parseInt(getElement().getStyle().getZIndex());
- } catch (Exception ignore) {
- // Ignored, will cause no harm
- zIndex = 1000;
- }
- if (zIndex == -1) {
- zIndex = Z_INDEX;
- }
- // Calculate position and size
- if (BrowserInfo.get().isIE()) {
- // Shake IE
- getOffsetHeight();
- getOffsetWidth();
- }
-
- if (isShadowEnabled() || needsShimElement()) {
-
- PositionAndSize positionAndSize = new PositionAndSize(
- getActualLeft(), getActualTop(), getOffsetWidth(),
- getOffsetHeight());
-
- // Animate the size
- positionAndSize.setAnimationFromCenterProgress(progress);
-
- Element container = getElement().getParentElement();
-
- if (isShadowEnabled()) {
- updateShadowPosition(progress, zIndex, positionAndSize);
- if (shadow.getParentElement() == null) {
- container.insertBefore(shadow, getElement());
- sinkShadowEvents();
- }
- }
-
- if (needsShimElement()) {
- updateShimPosition(positionAndSize);
- if (shimElement.getParentElement() == null) {
- container.insertBefore(shimElement, getElement());
- }
- }
- }
- // Fix for #14173
- // IE9 and IE10 have a bug, when resize an a element with box-shadow.
- // IE9 and IE10 need explicit update to remove extra box-shadows
- if (BrowserInfo.get().isIE9() || BrowserInfo.get().isIE10()) {
- WidgetUtil.forceIERedraw(getElement());
- }
- }
-
- /**
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- private void updateShadowPosition(final double progress, int zIndex,
- PositionAndSize positionAndSize) {
- // Opera needs some shaking to get parts of the shadow showing
- // properly (ticket #2704)
- if (BrowserInfo.get().isOpera()) {
- // Clear the height of all middle elements
- DOM.getChild(shadow, 3).getStyle().setProperty("height", "auto");
- DOM.getChild(shadow, 4).getStyle().setProperty("height", "auto");
- DOM.getChild(shadow, 5).getStyle().setProperty("height", "auto");
- }
-
- updatePositionAndSize(shadow, positionAndSize);
- shadow.getStyle().setZIndex(zIndex);
- shadow.getStyle().setProperty("display", progress < 0.9 ? "none" : "");
-
- // Opera fix, part 2 (ticket #2704)
- if (BrowserInfo.get().isOpera()) {
- // We'll fix the height of all the middle elements
- DOM.getChild(shadow, 3)
- .getStyle()
- .setPropertyPx("height",
- DOM.getChild(shadow, 3).getOffsetHeight());
- DOM.getChild(shadow, 4)
- .getStyle()
- .setPropertyPx("height",
- DOM.getChild(shadow, 4).getOffsetHeight());
- DOM.getChild(shadow, 5)
- .getStyle()
- .setPropertyPx("height",
- DOM.getChild(shadow, 5).getOffsetHeight());
- }
- }
-
- private void updateShimPosition(PositionAndSize positionAndSize) {
- updatePositionAndSize(getShimElement(), positionAndSize);
- }
-
- /**
- * Returns true if we should add a shim iframe below the overlay to deal
- * with zindex issues with PDFs and applets. Can be overriden to disable
- * shim iframes if they are not needed.
- *
- * @return true if a shim iframe should be added, false otherwise
- */
- protected boolean needsShimElement() {
- BrowserInfo info = BrowserInfo.get();
- return info.isIE() && info.isBrowserVersionNewerOrEqual(8, 0);
- }
-
- private void updatePositionAndSize(Element e,
- PositionAndSize positionAndSize) {
- e.getStyle().setLeft(positionAndSize.getLeft(), Unit.PX);
- e.getStyle().setTop(positionAndSize.getTop(), Unit.PX);
- e.getStyle().setWidth(positionAndSize.getWidth(), Unit.PX);
- e.getStyle().setHeight(positionAndSize.getHeight(), Unit.PX);
- }
-
- protected class ResizeAnimation extends Animation {
- @Override
- protected void onUpdate(double progress) {
- positionOrSizeUpdated(progress);
- }
- }
-
- @Override
- public void onClose(CloseEvent<PopupPanel> event) {
- removeShadowIfPresent();
- }
-
- @Override
- public void sinkEvents(int eventBitsToAdd) {
- super.sinkEvents(eventBitsToAdd);
- // Also sink events on the shadow if present
- sinkShadowEvents();
- }
-
- /**
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- private void sinkShadowEvents() {
- if (isSinkShadowEvents() && isShadowAttached()) {
- // Sink the same events as the actual overlay has sunk
- DOM.sinkEvents(shadow, DOM.getEventsSunk(getElement()));
- // Send events to VOverlay.onBrowserEvent
- DOM.setEventListener(shadow, this);
- }
- }
-
- /**
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- private void unsinkShadowEvents() {
- if (isShadowAttached()) {
- DOM.setEventListener(shadow, null);
- DOM.sinkEvents(shadow, 0);
- }
- }
-
- /**
- * Enables or disables sinking the events of the shadow to the same
- * onBrowserEvent as events to the actual overlay goes.
- *
- * Please note, that if you enable this, you can't assume that e.g.
- * event.getEventTarget returns an element inside the DOM structure of the
- * overlay
- *
- * @param sinkShadowEvents
- *
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- protected void setSinkShadowEvents(boolean sinkShadowEvents) {
- this.sinkShadowEvents = sinkShadowEvents;
- if (sinkShadowEvents) {
- sinkShadowEvents();
- } else {
- unsinkShadowEvents();
- }
- }
-
- /**
- * @deprecated See main JavaDoc for VOverlay
- */
- @Deprecated
- protected boolean isSinkShadowEvents() {
- return sinkShadowEvents;
- }
-
- /**
- * Get owner (Widget that made this VOverlay, not the layout parent) of
- * VOverlay
- *
- * @return Owner (creator) or null if not defined
- */
- public Widget getOwner() {
- return owner;
- }
-
- /**
- * Set owner (Widget that made this VOverlay, not the layout parent) of
- * VOverlay
- *
- * @param owner
- * Owner (creator) of VOverlay
- */
- public void setOwner(Widget owner) {
- this.owner = owner;
- }
-
- /**
- * Get the {@link ApplicationConnection} that this overlay belongs to. If
- * it's not set, {@link #getOwner()} is used to figure it out.
- *
- * @return
- */
- protected ApplicationConnection getApplicationConnection() {
- if (ac != null) {
- return ac;
- } else if (owner != null) {
- ComponentConnector c = Util.findConnectorFor(owner);
- if (c != null) {
- ac = c.getConnection();
- }
- return ac;
- } else {
- return null;
- }
- }
-
- /**
- * Gets the 'overlay container' element. Tries to find the current
- * {@link ApplicationConnection} using {@link #getApplicationConnection()}.
- *
- * @return the overlay container element for the current
- * {@link ApplicationConnection} or another element if the current
- * {@link ApplicationConnection} cannot be determined.
- */
- public com.google.gwt.user.client.Element getOverlayContainer() {
- ApplicationConnection ac = getApplicationConnection();
- if (ac == null) {
- // could not figure out which one we belong to, styling will
- // probably fail
- Logger.getLogger(getClass().getSimpleName())
- .log(Level.WARNING,
- "Could not determine ApplicationConnection for Overlay. Overlay will be attached directly to the root panel");
- return RootPanel.get().getElement();
- } else {
- return getOverlayContainer(ac);
- }
- }
-
- /**
- * Gets the 'overlay container' element pertaining to the given
- * {@link ApplicationConnection}. Each overlay should be created in a
- * overlay container element, so that the correct theme and styles can be
- * applied.
- *
- * @param ac
- * A reference to {@link ApplicationConnection}
- * @return The overlay container
- */
- public static com.google.gwt.user.client.Element getOverlayContainer(
- ApplicationConnection ac) {
- String id = ac.getConfiguration().getRootPanelId();
- id = id += "-overlays";
- Element container = DOM.getElementById(id);
- if (container == null) {
- container = DOM.createDiv();
- container.setId(id);
- String styles = ac.getUIConnector().getWidget().getParent()
- .getStyleName();
- if (styles != null && !styles.equals("")) {
- container.addClassName(styles);
- }
- container.addClassName(CLASSNAME_CONTAINER);
- RootPanel.get().getElement().appendChild(container);
- }
- return DOM.asOld(container);
- }
-
- /**
- * Set the label of the container element, where tooltip, notification and
- * dialgs are added to.
- *
- * @param applicationConnection
- * the application connection for which to change the label
- * @param overlayContainerLabel
- * label for the container
- */
- public static void setOverlayContainerLabel(
- ApplicationConnection applicationConnection,
- String overlayContainerLabel) {
- Roles.getAlertRole().setAriaLabelProperty(
- VOverlay.getOverlayContainer(applicationConnection),
- overlayContainerLabel);
- }
-
- @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;
- }-*/;
-
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.user.client.ui.PopupPanel#hide()
- */
- @Override
- public void hide() {
- hide(false);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.google.gwt.user.client.ui.PopupPanel#hide(boolean)
- */
- @Override
- public void hide(final boolean autoClosed) {
- hide(autoClosed, true, true);
- }
-
- /**
- *
- * Hides the popup and detaches it from the page. This has no effect if it
- * is not currently showing. Animation-in, animation-out can be
- * enable/disabled for different use cases.
- *
- * @see com.google.gwt.user.client.ui.PopupPanel#hide(boolean)
- *
- * @param autoClosed
- * the value that will be passed to
- * {@link CloseHandler#onClose(CloseEvent)} when the popup is
- * closed
- * @param animateIn
- * enable/disable animate-in animation
- * @param animateOut
- * enable/disable animate-out animation
- * @since 7.3.7
- */
- public void hide(final boolean autoClosed, final boolean animateIn,
- final boolean animateOut) {
- if (BrowserInfo.get().isIE8() || BrowserInfo.get().isIE9()) {
- super.hide(autoClosed);
- } else {
- if (animateIn
- && getStyleName().contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) {
- AnimationUtil.addAnimationEndListener(getElement(),
- new AnimationEndListener() {
- @Override
- public void onAnimationEnd(NativeEvent event) {
- if (AnimationUtil
- .getAnimationName(event)
- .contains(
- ADDITIONAL_CLASSNAME_ANIMATE_IN)) {
- VOverlay.this.hide(autoClosed);
- }
- }
- });
- } else {
- // Check if animations are used
- addStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT);
- if (isShadowEnabled()) {
- shadow.addClassName(CLASSNAME_SHADOW + "-"
- + ADDITIONAL_CLASSNAME_ANIMATE_OUT);
- }
- ComputedStyle cs = new ComputedStyle(getElement());
- String animationName = AnimationUtil.getAnimationName(cs);
- if (animationName == null) {
- animationName = "";
- }
-
- if (animateOut
- && animationName
- .contains(ADDITIONAL_CLASSNAME_ANIMATE_OUT)) {
- // Disable GWT PopupPanel closing animation if used
- setAnimationEnabled(false);
-
- AnimationUtil.addAnimationEndListener(getElement(),
- new AnimationEndListener() {
- @Override
- public void onAnimationEnd(NativeEvent event) {
- String animationName = AnimationUtil
- .getAnimationName(event);
- if (animationName
- .contains(ADDITIONAL_CLASSNAME_ANIMATE_OUT)) {
- AnimationUtil
- .removeAllAnimationEndListeners(getElement());
- // Remove both animation styles just in
- // case
- removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN);
- removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT);
- if (isShadowEnabled()) {
- shadow.removeClassName(CLASSNAME_SHADOW
- + "-"
- + ADDITIONAL_CLASSNAME_ANIMATE_IN);
- shadow.removeClassName(CLASSNAME_SHADOW
- + "-"
- + ADDITIONAL_CLASSNAME_ANIMATE_OUT);
- }
- VOverlay.super.hide(autoClosed);
- }
- }
- });
- // No event previews should happen after the animation has
- // started
- VOverlay.this.setPreviewingAllNativeEvents(false);
- } else {
- removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT);
- if (isShadowEnabled()) {
- shadow.removeClassName(CLASSNAME_SHADOW + "-"
- + ADDITIONAL_CLASSNAME_ANIMATE_OUT);
- }
- super.hide(autoClosed);
- }
- }
- }
- }
-
- }
|