You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VOverlay.java 36KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062
  1. /*
  2. * Copyright 2000-2014 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client.ui;
  17. import java.util.logging.Level;
  18. import java.util.logging.Logger;
  19. import com.google.gwt.animation.client.Animation;
  20. import com.google.gwt.aria.client.Roles;
  21. import com.google.gwt.core.client.JavaScriptObject;
  22. import com.google.gwt.dom.client.Document;
  23. import com.google.gwt.dom.client.Element;
  24. import com.google.gwt.dom.client.IFrameElement;
  25. import com.google.gwt.dom.client.NativeEvent;
  26. import com.google.gwt.dom.client.Style;
  27. import com.google.gwt.dom.client.Style.BorderStyle;
  28. import com.google.gwt.dom.client.Style.Position;
  29. import com.google.gwt.dom.client.Style.Unit;
  30. import com.google.gwt.event.logical.shared.CloseEvent;
  31. import com.google.gwt.event.logical.shared.CloseHandler;
  32. import com.google.gwt.user.client.DOM;
  33. import com.google.gwt.user.client.Window;
  34. import com.google.gwt.user.client.ui.PopupPanel;
  35. import com.google.gwt.user.client.ui.RootPanel;
  36. import com.google.gwt.user.client.ui.Widget;
  37. import com.vaadin.client.AnimationUtil;
  38. import com.vaadin.client.AnimationUtil.AnimationEndListener;
  39. import com.vaadin.client.ApplicationConnection;
  40. import com.vaadin.client.BrowserInfo;
  41. import com.vaadin.client.ComponentConnector;
  42. import com.vaadin.client.ComputedStyle;
  43. import com.vaadin.client.Util;
  44. /**
  45. * <p>
  46. * In Vaadin UI this Overlay should always be used for all elements that
  47. * temporary float over other components like context menus etc. This is to deal
  48. * stacking order correctly with VWindow objects.
  49. * </p>
  50. *
  51. * <h3>Shadow</h3>
  52. * <p>
  53. * The separate shadow element underneath the main overlay element is <strong>
  54. * <em>deprecated</em></strong>, and should not be used for new overlay
  55. * components. CSS box-shadow should be used instead of a separate shadow
  56. * element. Remember to include any vendor-prefixed versions to support all
  57. * browsers that you need to. To cover all possible browsers that Vaadin 7
  58. * supports, add <code>-webkit-box-shadow</code> and the standard
  59. * <code>box-shadow</code> properties.
  60. * </p>
  61. *
  62. * <p>
  63. * For IE8, which doesn't support CSS box-shadow, you can use the proprietary
  64. * DropShadow filter. It doesn't provide the exact same features as box-shadow,
  65. * but it is suitable for graceful degradation. Other options are to use a
  66. * border or a pseudo-element underneath the overlay which mimics a shadow, or
  67. * any combination of these.
  68. * </p>
  69. *
  70. * <p>
  71. * Read more about the DropShadow filter from <a
  72. * href="http://msdn.microsoft.com/en-us/library/ms532985(v=vs.85).aspx"
  73. * >Microsoft Developer Network</a>
  74. * </p>
  75. */
  76. public class VOverlay extends PopupPanel implements CloseHandler<PopupPanel> {
  77. public static class PositionAndSize {
  78. private int left, top, width, height;
  79. public PositionAndSize(int left, int top, int width, int height) {
  80. super();
  81. setLeft(left);
  82. setTop(top);
  83. setWidth(width);
  84. setHeight(height);
  85. }
  86. public int getLeft() {
  87. return left;
  88. }
  89. public void setLeft(int left) {
  90. this.left = left;
  91. }
  92. public int getTop() {
  93. return top;
  94. }
  95. public void setTop(int top) {
  96. this.top = top;
  97. }
  98. public int getWidth() {
  99. return width;
  100. }
  101. public void setWidth(int width) {
  102. if (width < 0) {
  103. width = 0;
  104. }
  105. this.width = width;
  106. }
  107. public int getHeight() {
  108. return height;
  109. }
  110. public void setHeight(int height) {
  111. if (height < 0) {
  112. height = 0;
  113. }
  114. this.height = height;
  115. }
  116. public void setAnimationFromCenterProgress(double progress) {
  117. left += (int) (width * (1.0 - progress) / 2.0);
  118. top += (int) (height * (1.0 - progress) / 2.0);
  119. width = (int) (width * progress);
  120. height = (int) (height * progress);
  121. }
  122. }
  123. /*
  124. * The z-index value from where all overlays live. This can be overridden in
  125. * any extending class.
  126. */
  127. public static int Z_INDEX = 20000;
  128. private static int leftFix = -1;
  129. private static int topFix = -1;
  130. /**
  131. * Shadow element style. If an extending class wishes to use a different
  132. * style of shadow, it can use setShadowStyle(String) to give the shadow
  133. * element a new style name.
  134. *
  135. * @deprecated See main JavaDoc for VOverlay
  136. */
  137. @Deprecated
  138. public static final String CLASSNAME_SHADOW = "v-shadow";
  139. /**
  140. * Style name for the overlay container element (see
  141. * {@link #getOverlayContainer()}
  142. */
  143. public static final String CLASSNAME_CONTAINER = "v-overlay-container";
  144. /**
  145. * @since 7.3
  146. */
  147. public static final String ADDITIONAL_CLASSNAME_ANIMATE_IN = "animate-in";
  148. /**
  149. * @since 7.3
  150. */
  151. public static final String ADDITIONAL_CLASSNAME_ANIMATE_OUT = "animate-out";
  152. /**
  153. * The shadow element for this overlay.
  154. *
  155. * @deprecated See main JavaDoc for VOverlay
  156. *
  157. */
  158. @Deprecated
  159. private Element shadow;
  160. /*
  161. * The creator of this VOverlay (the widget that made the instance, not the
  162. * layout parent)
  163. */
  164. private Widget owner;
  165. /*
  166. * ApplicationConnection that this overlay belongs to, which is needed to
  167. * create the overlay in the correct container so that the correct styles
  168. * are applied. If not given, owner will be used to figure out, and as a
  169. * last fallback, the overlay is created w/o container, potentially missing
  170. * styles.
  171. */
  172. protected ApplicationConnection ac;
  173. /**
  174. * The shim iframe behind the overlay, allowing PDFs and applets to be
  175. * covered by overlays.
  176. */
  177. private IFrameElement shimElement;
  178. /**
  179. * The HTML snippet that is used to render the actual shadow. In consists of
  180. * nine different DIV-elements with the following class names:
  181. *
  182. * <pre>
  183. * .v-shadow[-stylename]
  184. * ----------------------------------------------
  185. * | .top-left | .top | .top-right |
  186. * |---------------|-----------|----------------|
  187. * | | | |
  188. * | .left | .center | .right |
  189. * | | | |
  190. * |---------------|-----------|----------------|
  191. * | .bottom-left | .bottom | .bottom-right |
  192. * ----------------------------------------------
  193. * </pre>
  194. *
  195. * See default theme 'shadow.css' for implementation example.
  196. *
  197. * @deprecated See main JavaDoc for VOverlay
  198. */
  199. @Deprecated
  200. 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>";
  201. /**
  202. * Matches {@link PopupPanel}.ANIMATION_DURATION
  203. */
  204. private static final int POPUP_PANEL_ANIMATION_DURATION = 200;
  205. /**
  206. * @deprecated See main JavaDoc for VOverlay
  207. */
  208. @Deprecated
  209. private boolean sinkShadowEvents = false;
  210. public VOverlay() {
  211. super();
  212. adjustZIndex();
  213. }
  214. public VOverlay(boolean autoHide) {
  215. super(autoHide);
  216. adjustZIndex();
  217. }
  218. public VOverlay(boolean autoHide, boolean modal) {
  219. super(autoHide, modal);
  220. adjustZIndex();
  221. }
  222. /**
  223. * @deprecated See main JavaDoc for VOverlay. Use the other constructors
  224. * without the <code>showShadow</code> parameter.
  225. */
  226. @Deprecated
  227. public VOverlay(boolean autoHide, boolean modal, boolean showShadow) {
  228. super(autoHide, modal);
  229. setShadowEnabled(showShadow && useShadowDiv());
  230. adjustZIndex();
  231. }
  232. /**
  233. * Return true if a separate shadow div should be used. Since Vaadin 7.3,
  234. * shadows are implemented with CSS box-shadow. Thus, a shadow div is only
  235. * used for IE8 by default.
  236. *
  237. * @deprecated See main JavaDoc for VOverlay
  238. * @since 7.3
  239. * @return true to use a shadow div
  240. */
  241. @Deprecated
  242. protected boolean useShadowDiv() {
  243. return BrowserInfo.get().isIE8();
  244. }
  245. /**
  246. * Method to control whether DOM elements for shadow are added. With this
  247. * method subclasses can control displaying of shadow also after the
  248. * constructor.
  249. *
  250. * @param enabled
  251. * true if shadow should be displayed
  252. *
  253. * @deprecated See main JavaDoc for VOverlay
  254. */
  255. @Deprecated
  256. protected void setShadowEnabled(boolean enabled) {
  257. if (enabled != isShadowEnabled()) {
  258. if (enabled) {
  259. shadow = DOM.createDiv();
  260. shadow.setClassName(CLASSNAME_SHADOW);
  261. shadow.setInnerHTML(SHADOW_HTML);
  262. shadow.getStyle().setPosition(Position.ABSOLUTE);
  263. addCloseHandler(this);
  264. } else {
  265. removeShadowIfPresent();
  266. shadow = null;
  267. }
  268. }
  269. }
  270. /**
  271. * @deprecated See main JavaDoc for VOverlay
  272. */
  273. @Deprecated
  274. protected boolean isShadowEnabled() {
  275. return shadow != null;
  276. }
  277. protected boolean isShimElementEnabled() {
  278. return shimElement != null;
  279. }
  280. private void removeShimElement() {
  281. if (shimElement != null) {
  282. shimElement.removeFromParent();
  283. }
  284. }
  285. /**
  286. * @deprecated See main JavaDoc for VOverlay
  287. */
  288. @Deprecated
  289. private void removeShadowIfPresent() {
  290. if (isShadowAttached()) {
  291. // Remove event listener from the shadow
  292. unsinkShadowEvents();
  293. shadow.removeFromParent();
  294. }
  295. }
  296. /**
  297. * @deprecated See main JavaDoc for VOverlay
  298. */
  299. @Deprecated
  300. private boolean isShadowAttached() {
  301. return isShadowEnabled() && shadow.getParentElement() != null;
  302. }
  303. private void adjustZIndex() {
  304. setZIndex(Z_INDEX);
  305. }
  306. /**
  307. * Set the z-index (visual stack position) for this overlay.
  308. *
  309. * @param zIndex
  310. * The new z-index
  311. */
  312. protected void setZIndex(int zIndex) {
  313. getElement().getStyle().setZIndex(zIndex);
  314. if (isShadowEnabled()) {
  315. shadow.getStyle().setZIndex(zIndex);
  316. }
  317. }
  318. @Override
  319. public void setPopupPosition(int left, int top) {
  320. // TODO, this should in fact be part of
  321. // Document.get().getBodyOffsetLeft/Top(). Would require overriding DOM
  322. // for all permutations. Now adding fix as margin instead of fixing
  323. // left/top because parent class saves the position.
  324. Style style = getElement().getStyle();
  325. style.setMarginLeft(-adjustByRelativeLeftBodyMargin(), Unit.PX);
  326. style.setMarginTop(-adjustByRelativeTopBodyMargin(), Unit.PX);
  327. super.setPopupPosition(left, top);
  328. positionOrSizeUpdated(isAnimationEnabled() ? 0 : 1);
  329. }
  330. private IFrameElement getShimElement() {
  331. if (shimElement == null && needsShimElement()) {
  332. shimElement = Document.get().createIFrameElement();
  333. // Insert shim iframe before the main overlay element. It does not
  334. // matter if it is in front or behind the shadow as we cannot put a
  335. // shim behind the shadow due to its transparency.
  336. shimElement.getStyle().setPosition(Position.ABSOLUTE);
  337. shimElement.getStyle().setBorderStyle(BorderStyle.NONE);
  338. shimElement.setTabIndex(-1);
  339. shimElement.setFrameBorder(0);
  340. shimElement.setMarginHeight(0);
  341. }
  342. return shimElement;
  343. }
  344. private int getActualTop() {
  345. int y = getAbsoluteTop();
  346. /* This is needed for IE7 at least */
  347. // Account for the difference between absolute position and the
  348. // body's positioning context.
  349. y -= Document.get().getBodyOffsetTop();
  350. y -= adjustByRelativeTopBodyMargin();
  351. return y;
  352. }
  353. private int getActualLeft() {
  354. int x = getAbsoluteLeft();
  355. /* This is needed for IE7 at least */
  356. // Account for the difference between absolute position and the
  357. // body's positioning context.
  358. x -= Document.get().getBodyOffsetLeft();
  359. x -= adjustByRelativeLeftBodyMargin();
  360. return x;
  361. }
  362. private static int adjustByRelativeTopBodyMargin() {
  363. if (topFix == -1) {
  364. topFix = detectRelativeBodyFixes("top");
  365. }
  366. return topFix;
  367. }
  368. private native static int detectRelativeBodyFixes(String axis)
  369. /*-{
  370. try {
  371. var b = $wnd.document.body;
  372. var cstyle = b.currentStyle ? b.currentStyle : getComputedStyle(b);
  373. if(cstyle && cstyle.position == 'relative') {
  374. return b.getBoundingClientRect()[axis];
  375. }
  376. } catch(e){}
  377. return 0;
  378. }-*/;
  379. private static int adjustByRelativeLeftBodyMargin() {
  380. if (leftFix == -1) {
  381. leftFix = detectRelativeBodyFixes("left");
  382. }
  383. return leftFix;
  384. }
  385. /*
  386. * A "thread local" of sorts, set temporarily so that VOverlayImpl knows
  387. * which VOverlay is using it, so that it can be attached to the correct
  388. * overlay container.
  389. *
  390. * TODO this is a strange pattern that we should get rid of when possible.
  391. */
  392. protected static VOverlay current;
  393. @Override
  394. public void show() {
  395. current = this;
  396. maybeShowWithAnimation();
  397. if (isAnimationEnabled()) {
  398. new ResizeAnimation().run(POPUP_PANEL_ANIMATION_DURATION);
  399. } else {
  400. positionOrSizeUpdated(1.0);
  401. }
  402. current = null;
  403. }
  404. private JavaScriptObject animateInListener;
  405. private boolean maybeShowWithAnimation() {
  406. boolean isAttached = isAttached() && isShowing();
  407. super.show();
  408. // Don't animate if already visible or browser is IE8 or IE9 (no CSS
  409. // animation support)
  410. if (isAttached || BrowserInfo.get().isIE8()
  411. || BrowserInfo.get().isIE9()) {
  412. return false;
  413. } else {
  414. // Check if animations are used
  415. setVisible(false);
  416. addStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN);
  417. if (isShadowEnabled()) {
  418. shadow.addClassName(CLASSNAME_SHADOW + "-"
  419. + ADDITIONAL_CLASSNAME_ANIMATE_IN);
  420. }
  421. ComputedStyle cs = new ComputedStyle(getElement());
  422. String animationName = AnimationUtil.getAnimationName(cs);
  423. if (animationName == null) {
  424. animationName = "";
  425. }
  426. setVisible(true);
  427. if (animationName.contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) {
  428. // Disable GWT PopupPanel animation if used
  429. setAnimationEnabled(false);
  430. animateInListener = AnimationUtil.addAnimationEndListener(
  431. getElement(), new AnimationEndListener() {
  432. @Override
  433. public void onAnimationEnd(NativeEvent event) {
  434. String animationName = AnimationUtil
  435. .getAnimationName(event);
  436. if (animationName
  437. .contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) {
  438. AnimationUtil.removeAnimationEndListener(
  439. getElement(), animateInListener);
  440. removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN);
  441. if (isShadowEnabled()) {
  442. shadow.removeClassName(CLASSNAME_SHADOW
  443. + "-"
  444. + ADDITIONAL_CLASSNAME_ANIMATE_IN);
  445. }
  446. }
  447. }
  448. });
  449. return true;
  450. } else {
  451. removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN);
  452. if (isShadowEnabled()) {
  453. shadow.removeClassName(CLASSNAME_SHADOW + "-"
  454. + ADDITIONAL_CLASSNAME_ANIMATE_IN);
  455. }
  456. return false;
  457. }
  458. }
  459. }
  460. @Override
  461. protected void onDetach() {
  462. super.onDetach();
  463. // Always ensure shadow is removed when the overlay is removed.
  464. removeShadowIfPresent();
  465. removeShimElement();
  466. }
  467. @Override
  468. public void setVisible(boolean visible) {
  469. super.setVisible(visible);
  470. if (isShadowEnabled()) {
  471. shadow.getStyle().setProperty("visibility",
  472. visible ? "visible" : "hidden");
  473. }
  474. if (isShimElementEnabled()) {
  475. shimElement.getStyle().setProperty("visibility",
  476. visible ? "visible" : "hidden");
  477. }
  478. }
  479. @Override
  480. public void setWidth(String width) {
  481. super.setWidth(width);
  482. positionOrSizeUpdated(1.0);
  483. }
  484. @Override
  485. public void setHeight(String height) {
  486. super.setHeight(height);
  487. positionOrSizeUpdated(1.0);
  488. }
  489. /**
  490. * Sets the shadow style for this overlay. Will override any previous style
  491. * for the shadow. The default style name is defined by CLASSNAME_SHADOW.
  492. * The given style will be prefixed with CLASSNAME_SHADOW.
  493. *
  494. * @param style
  495. * The new style name for the shadow element. Will be prefixed by
  496. * CLASSNAME_SHADOW, e.g. style=='foobar' -> actual style
  497. * name=='v-shadow-foobar'.
  498. *
  499. * @deprecated See main JavaDoc for VOverlay
  500. */
  501. @Deprecated
  502. protected void setShadowStyle(String style) {
  503. if (isShadowEnabled()) {
  504. shadow.setClassName(CLASSNAME_SHADOW + "-" + style);
  505. }
  506. }
  507. /**
  508. * Extending classes should always call this method after they change the
  509. * size of overlay without using normal 'setWidth(String)' and
  510. * 'setHeight(String)' methods (if not calling super.setWidth/Height).
  511. *
  512. */
  513. public void positionOrSizeUpdated() {
  514. positionOrSizeUpdated(1.0);
  515. }
  516. /**
  517. * @deprecated Call {@link #positionOrSizeUpdated()} instead.
  518. */
  519. @Deprecated
  520. protected void updateShadowSizeAndPosition() {
  521. positionOrSizeUpdated();
  522. }
  523. /**
  524. * Recalculates proper position and dimensions for the shadow and shim
  525. * elements. Can be used to animate the related elements, using the
  526. * 'progress' parameter (used to animate the shadow in sync with GWT
  527. * PopupPanel's default animation 'PopupPanel.AnimationType.CENTER').
  528. *
  529. * @param progress
  530. * A value between 0.0 and 1.0, indicating the progress of the
  531. * animation (0=start, 1=end).
  532. */
  533. private void positionOrSizeUpdated(final double progress) {
  534. // Don't do anything if overlay element is not attached
  535. if (!isAttached()) {
  536. return;
  537. }
  538. // Calculate proper z-index
  539. int zIndex = -1;
  540. try {
  541. // Odd behaviour with Windows Hosted Mode forces us to use
  542. // this redundant try/catch block (See dev.vaadin.com #2011)
  543. zIndex = Integer.parseInt(getElement().getStyle().getZIndex());
  544. } catch (Exception ignore) {
  545. // Ignored, will cause no harm
  546. zIndex = 1000;
  547. }
  548. if (zIndex == -1) {
  549. zIndex = Z_INDEX;
  550. }
  551. // Calculate position and size
  552. if (BrowserInfo.get().isIE()) {
  553. // Shake IE
  554. getOffsetHeight();
  555. getOffsetWidth();
  556. }
  557. if (isShadowEnabled() || needsShimElement()) {
  558. PositionAndSize positionAndSize = new PositionAndSize(
  559. getActualLeft(), getActualTop(), getOffsetWidth(),
  560. getOffsetHeight());
  561. // Animate the size
  562. positionAndSize.setAnimationFromCenterProgress(progress);
  563. Element container = getElement().getParentElement();
  564. if (isShadowEnabled()) {
  565. updateShadowPosition(progress, zIndex, positionAndSize);
  566. if (shadow.getParentElement() == null) {
  567. container.insertBefore(shadow, getElement());
  568. sinkShadowEvents();
  569. }
  570. }
  571. if (needsShimElement()) {
  572. updateShimPosition(positionAndSize);
  573. if (shimElement.getParentElement() == null) {
  574. container.insertBefore(shimElement, getElement());
  575. }
  576. }
  577. }
  578. // Fix for #14173
  579. // IE9 and IE10 have a bug, when resize an a element with box-shadow.
  580. // IE9 and IE10 need explicit update to remove extra box-shadows
  581. if (BrowserInfo.get().isIE9() || BrowserInfo.get().isIE10()) {
  582. Util.forceIERedraw(getElement());
  583. }
  584. }
  585. /**
  586. * @deprecated See main JavaDoc for VOverlay
  587. */
  588. @Deprecated
  589. private void updateShadowPosition(final double progress, int zIndex,
  590. PositionAndSize positionAndSize) {
  591. // Opera needs some shaking to get parts of the shadow showing
  592. // properly (ticket #2704)
  593. if (BrowserInfo.get().isOpera()) {
  594. // Clear the height of all middle elements
  595. DOM.getChild(shadow, 3).getStyle().setProperty("height", "auto");
  596. DOM.getChild(shadow, 4).getStyle().setProperty("height", "auto");
  597. DOM.getChild(shadow, 5).getStyle().setProperty("height", "auto");
  598. }
  599. updatePositionAndSize(shadow, positionAndSize);
  600. shadow.getStyle().setZIndex(zIndex);
  601. shadow.getStyle().setProperty("display", progress < 0.9 ? "none" : "");
  602. // Opera fix, part 2 (ticket #2704)
  603. if (BrowserInfo.get().isOpera()) {
  604. // We'll fix the height of all the middle elements
  605. DOM.getChild(shadow, 3)
  606. .getStyle()
  607. .setPropertyPx("height",
  608. DOM.getChild(shadow, 3).getOffsetHeight());
  609. DOM.getChild(shadow, 4)
  610. .getStyle()
  611. .setPropertyPx("height",
  612. DOM.getChild(shadow, 4).getOffsetHeight());
  613. DOM.getChild(shadow, 5)
  614. .getStyle()
  615. .setPropertyPx("height",
  616. DOM.getChild(shadow, 5).getOffsetHeight());
  617. }
  618. }
  619. private void updateShimPosition(PositionAndSize positionAndSize) {
  620. updatePositionAndSize(getShimElement(), positionAndSize);
  621. }
  622. /**
  623. * Returns true if we should add a shim iframe below the overlay to deal
  624. * with zindex issues with PDFs and applets. Can be overriden to disable
  625. * shim iframes if they are not needed.
  626. *
  627. * @return true if a shim iframe should be added, false otherwise
  628. */
  629. protected boolean needsShimElement() {
  630. BrowserInfo info = BrowserInfo.get();
  631. return info.isIE() && info.isBrowserVersionNewerOrEqual(8, 0);
  632. }
  633. private void updatePositionAndSize(Element e,
  634. PositionAndSize positionAndSize) {
  635. e.getStyle().setLeft(positionAndSize.getLeft(), Unit.PX);
  636. e.getStyle().setTop(positionAndSize.getTop(), Unit.PX);
  637. e.getStyle().setWidth(positionAndSize.getWidth(), Unit.PX);
  638. e.getStyle().setHeight(positionAndSize.getHeight(), Unit.PX);
  639. }
  640. protected class ResizeAnimation extends Animation {
  641. @Override
  642. protected void onUpdate(double progress) {
  643. positionOrSizeUpdated(progress);
  644. }
  645. }
  646. @Override
  647. public void onClose(CloseEvent<PopupPanel> event) {
  648. removeShadowIfPresent();
  649. }
  650. @Override
  651. public void sinkEvents(int eventBitsToAdd) {
  652. super.sinkEvents(eventBitsToAdd);
  653. // Also sink events on the shadow if present
  654. sinkShadowEvents();
  655. }
  656. /**
  657. * @deprecated See main JavaDoc for VOverlay
  658. */
  659. @Deprecated
  660. private void sinkShadowEvents() {
  661. if (isSinkShadowEvents() && isShadowAttached()) {
  662. // Sink the same events as the actual overlay has sunk
  663. DOM.sinkEvents(shadow, DOM.getEventsSunk(getElement()));
  664. // Send events to VOverlay.onBrowserEvent
  665. DOM.setEventListener(shadow, this);
  666. }
  667. }
  668. /**
  669. * @deprecated See main JavaDoc for VOverlay
  670. */
  671. @Deprecated
  672. private void unsinkShadowEvents() {
  673. if (isShadowAttached()) {
  674. DOM.setEventListener(shadow, null);
  675. DOM.sinkEvents(shadow, 0);
  676. }
  677. }
  678. /**
  679. * Enables or disables sinking the events of the shadow to the same
  680. * onBrowserEvent as events to the actual overlay goes.
  681. *
  682. * Please note, that if you enable this, you can't assume that e.g.
  683. * event.getEventTarget returns an element inside the DOM structure of the
  684. * overlay
  685. *
  686. * @param sinkShadowEvents
  687. *
  688. * @deprecated See main JavaDoc for VOverlay
  689. */
  690. @Deprecated
  691. protected void setSinkShadowEvents(boolean sinkShadowEvents) {
  692. this.sinkShadowEvents = sinkShadowEvents;
  693. if (sinkShadowEvents) {
  694. sinkShadowEvents();
  695. } else {
  696. unsinkShadowEvents();
  697. }
  698. }
  699. /**
  700. * @deprecated See main JavaDoc for VOverlay
  701. */
  702. @Deprecated
  703. protected boolean isSinkShadowEvents() {
  704. return sinkShadowEvents;
  705. }
  706. /**
  707. * Get owner (Widget that made this VOverlay, not the layout parent) of
  708. * VOverlay
  709. *
  710. * @return Owner (creator) or null if not defined
  711. */
  712. public Widget getOwner() {
  713. return owner;
  714. }
  715. /**
  716. * Set owner (Widget that made this VOverlay, not the layout parent) of
  717. * VOverlay
  718. *
  719. * @param owner
  720. * Owner (creator) of VOverlay
  721. */
  722. public void setOwner(Widget owner) {
  723. this.owner = owner;
  724. }
  725. /**
  726. * Get the {@link ApplicationConnection} that this overlay belongs to. If
  727. * it's not set, {@link #getOwner()} is used to figure it out.
  728. *
  729. * @return
  730. */
  731. protected ApplicationConnection getApplicationConnection() {
  732. if (ac != null) {
  733. return ac;
  734. } else if (owner != null) {
  735. ComponentConnector c = Util.findConnectorFor(owner);
  736. if (c != null) {
  737. ac = c.getConnection();
  738. }
  739. return ac;
  740. } else {
  741. return null;
  742. }
  743. }
  744. /**
  745. * Gets the 'overlay container' element. Tries to find the current
  746. * {@link ApplicationConnection} using {@link #getApplicationConnection()}.
  747. *
  748. * @return the overlay container element for the current
  749. * {@link ApplicationConnection} or another element if the current
  750. * {@link ApplicationConnection} cannot be determined.
  751. */
  752. public com.google.gwt.user.client.Element getOverlayContainer() {
  753. ApplicationConnection ac = getApplicationConnection();
  754. if (ac == null) {
  755. // could not figure out which one we belong to, styling will
  756. // probably fail
  757. Logger.getLogger(getClass().getSimpleName())
  758. .log(Level.WARNING,
  759. "Could not determine ApplicationConnection for Overlay. Overlay will be attached directly to the root panel");
  760. return RootPanel.get().getElement();
  761. } else {
  762. return getOverlayContainer(ac);
  763. }
  764. }
  765. /**
  766. * Gets the 'overlay container' element pertaining to the given
  767. * {@link ApplicationConnection}. Each overlay should be created in a
  768. * overlay container element, so that the correct theme and styles can be
  769. * applied.
  770. *
  771. * @param ac
  772. * A reference to {@link ApplicationConnection}
  773. * @return The overlay container
  774. */
  775. public static com.google.gwt.user.client.Element getOverlayContainer(
  776. ApplicationConnection ac) {
  777. String id = ac.getConfiguration().getRootPanelId();
  778. id = id += "-overlays";
  779. Element container = DOM.getElementById(id);
  780. if (container == null) {
  781. container = DOM.createDiv();
  782. container.setId(id);
  783. String styles = ac.getUIConnector().getWidget().getParent()
  784. .getStyleName();
  785. container.addClassName(styles);
  786. container.addClassName(CLASSNAME_CONTAINER);
  787. RootPanel.get().getElement().appendChild(container);
  788. }
  789. return DOM.asOld(container);
  790. }
  791. /**
  792. * Set the label of the container element, where tooltip, notification and
  793. * dialgs are added to.
  794. *
  795. * @param applicationConnection
  796. * the application connection for which to change the label
  797. * @param overlayContainerLabel
  798. * label for the container
  799. */
  800. public static void setOverlayContainerLabel(
  801. ApplicationConnection applicationConnection,
  802. String overlayContainerLabel) {
  803. Roles.getAlertRole().setAriaLabelProperty(
  804. VOverlay.getOverlayContainer(applicationConnection),
  805. overlayContainerLabel);
  806. }
  807. @Override
  808. public void center() {
  809. super.center();
  810. // Some devices can be zoomed in, we should center to the visual
  811. // viewport for those devices
  812. BrowserInfo b = BrowserInfo.get();
  813. if (b.isAndroid() || b.isIOS()) {
  814. int left = (getVisualViewportWidth() - getOffsetWidth()) >> 1;
  815. int top = (getVisualViewportHeight() - getOffsetHeight()) >> 1;
  816. setPopupPosition(Math.max(Window.getScrollLeft() + left, 0),
  817. Math.max(Window.getScrollTop() + top, 0));
  818. }
  819. }
  820. /**
  821. * Gets the visual viewport width, which is useful for e.g iOS where the
  822. * view can be zoomed in while keeping the layout viewport intact.
  823. *
  824. * Falls back to layout viewport; for those browsers/devices the difference
  825. * is that the scrollbar with is included (if there is a scrollbar).
  826. *
  827. * @since 7.0.7
  828. * @return
  829. */
  830. private int getVisualViewportWidth() {
  831. int w = (int) getSubpixelInnerWidth();
  832. if (w < 0) {
  833. return Window.getClientWidth();
  834. } else {
  835. return w;
  836. }
  837. }
  838. /**
  839. * Gets the visual viewport height, which is useful for e.g iOS where the
  840. * view can be zoomed in while keeping the layout viewport intact.
  841. *
  842. * Falls back to layout viewport; for those browsers/devices the difference
  843. * is that the scrollbar with is included (if there is a scrollbar).
  844. *
  845. * @since 7.0.7
  846. * @return
  847. */
  848. private int getVisualViewportHeight() {
  849. int h = (int) getSubpixelInnerHeight();
  850. if (h < 0) {
  851. return Window.getClientHeight();
  852. } else {
  853. return h;
  854. }
  855. }
  856. private native double getSubpixelInnerWidth()
  857. /*-{
  858. return $wnd.innerWidth !== undefined ? $wnd.innerWidth : -1;
  859. }-*/;
  860. private native double getSubpixelInnerHeight()
  861. /*-{
  862. return $wnd.innerHeight !== undefined ? $wnd.innerHeight :-1;
  863. }-*/;
  864. /*
  865. * (non-Javadoc)
  866. *
  867. * @see com.google.gwt.user.client.ui.PopupPanel#hide()
  868. */
  869. @Override
  870. public void hide() {
  871. hide(false);
  872. }
  873. /*
  874. * (non-Javadoc)
  875. *
  876. * @see com.google.gwt.user.client.ui.PopupPanel#hide(boolean)
  877. */
  878. @Override
  879. public void hide(final boolean autoClosed) {
  880. if (BrowserInfo.get().isIE8() || BrowserInfo.get().isIE9()) {
  881. super.hide(autoClosed);
  882. } else {
  883. if (getStyleName().contains(ADDITIONAL_CLASSNAME_ANIMATE_IN)) {
  884. AnimationUtil.addAnimationEndListener(getElement(),
  885. new AnimationEndListener() {
  886. @Override
  887. public void onAnimationEnd(NativeEvent event) {
  888. if (AnimationUtil
  889. .getAnimationName(event)
  890. .contains(
  891. ADDITIONAL_CLASSNAME_ANIMATE_IN)) {
  892. VOverlay.this.hide(autoClosed);
  893. }
  894. }
  895. });
  896. } else {
  897. // Check if animations are used
  898. addStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT);
  899. if (isShadowEnabled()) {
  900. shadow.addClassName(CLASSNAME_SHADOW + "-"
  901. + ADDITIONAL_CLASSNAME_ANIMATE_OUT);
  902. }
  903. ComputedStyle cs = new ComputedStyle(getElement());
  904. String animationName = AnimationUtil.getAnimationName(cs);
  905. if (animationName == null) {
  906. animationName = "";
  907. }
  908. if (animationName.contains(ADDITIONAL_CLASSNAME_ANIMATE_OUT)) {
  909. // Disable GWT PopupPanel closing animation if used
  910. setAnimationEnabled(false);
  911. AnimationUtil.addAnimationEndListener(getElement(),
  912. new AnimationEndListener() {
  913. @Override
  914. public void onAnimationEnd(NativeEvent event) {
  915. String animationName = AnimationUtil
  916. .getAnimationName(event);
  917. if (animationName
  918. .contains(ADDITIONAL_CLASSNAME_ANIMATE_OUT)) {
  919. AnimationUtil
  920. .removeAllAnimationEndListeners(getElement());
  921. // Remove both animation styles just in
  922. // case
  923. removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_IN);
  924. removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT);
  925. if (isShadowEnabled()) {
  926. shadow.removeClassName(CLASSNAME_SHADOW
  927. + "-"
  928. + ADDITIONAL_CLASSNAME_ANIMATE_IN);
  929. shadow.removeClassName(CLASSNAME_SHADOW
  930. + "-"
  931. + ADDITIONAL_CLASSNAME_ANIMATE_OUT);
  932. }
  933. VOverlay.super.hide(autoClosed);
  934. }
  935. }
  936. });
  937. // No event previews should happen after the animation has
  938. // started
  939. VOverlay.this.setPreviewingAllNativeEvents(false);
  940. } else {
  941. removeStyleDependentName(ADDITIONAL_CLASSNAME_ANIMATE_OUT);
  942. if (isShadowEnabled()) {
  943. shadow.removeClassName(CLASSNAME_SHADOW + "-"
  944. + ADDITIONAL_CLASSNAME_ANIMATE_OUT);
  945. }
  946. super.hide(autoClosed);
  947. }
  948. }
  949. }
  950. }
  951. }