diff options
author | Artur <artur@vaadin.com> | 2017-03-27 11:14:49 +0300 |
---|---|---|
committer | Pekka Hyvönen <pekka@vaadin.com> | 2017-03-27 11:14:49 +0300 |
commit | 2fe4c50ac802533e0057ebb8ce0c3c5d1bf50b4b (patch) | |
tree | ab820fb9a2e138476ea6a75fd89d1e88a40090d2 /client | |
parent | 9b7d34fc41c0e088069455639cca2f32750291f6 (diff) | |
download | vaadin-framework-2fe4c50ac802533e0057ebb8ce0c3c5d1bf50b4b.tar.gz vaadin-framework-2fe4c50ac802533e0057ebb8ce0c3c5d1bf50b4b.zip |
Use computed style for Escalator size calculations (#8861)
* Use computed style for Escalator size calculations
The old method of using getBoundingClientRect does not work as expected
if a transform has been applied to the element or one of its parents.
For instance PopupView animates itself using a scale(0) -> scale(1)
animation. When scale(0) is active, getBoundingClientRect will return 0
for all sizes while computed style ignores the transform and returns the
expected value.
Fixes #8793
Diffstat (limited to 'client')
-rw-r--r-- | client/src/main/java/com/vaadin/client/ComputedStyle.java | 113 | ||||
-rw-r--r-- | client/src/main/java/com/vaadin/client/widgets/Escalator.java | 59 |
2 files changed, 113 insertions, 59 deletions
diff --git a/client/src/main/java/com/vaadin/client/ComputedStyle.java b/client/src/main/java/com/vaadin/client/ComputedStyle.java index 977da6bafc..e9108f2ee6 100644 --- a/client/src/main/java/com/vaadin/client/ComputedStyle.java +++ b/client/src/main/java/com/vaadin/client/ComputedStyle.java @@ -20,6 +20,7 @@ import com.google.gwt.dom.client.Element; public class ComputedStyle { + private static final String CONTENT_BOX = "content-box"; protected final JavaScriptObject computedStyle; private final Element elem; @@ -32,7 +33,6 @@ public class ComputedStyle { * * @param elem * the element - * @return the computed style */ public ComputedStyle(Element elem) { computedStyle = getComputedStyle(elem); @@ -44,17 +44,18 @@ public class ComputedStyle { if(elem.nodeType != 1) { return {}; } - + if($wnd.document.defaultView && $wnd.document.defaultView.getComputedStyle) { return $wnd.document.defaultView.getComputedStyle(elem, null); } - + if(elem.currentStyle) { return elem.currentStyle; } }-*/; /** + * Gets the value of the given property. * * @param name * name of the CSS property in camelCase @@ -65,7 +66,7 @@ public class ComputedStyle { /*-{ var cs = this.@com.vaadin.client.ComputedStyle::computedStyle; var elem = this.@com.vaadin.client.ComputedStyle::elem; - + // Border values need to be checked separately. The width might have a // meaningful value even if the border style is "none". In that case the // value should be 0. @@ -78,45 +79,45 @@ public class ComputedStyle { if(borderStyle == "none") return "0px"; } - + if(cs.getPropertyValue) { - + // Convert name to dashed format name = name.replace(/([A-Z])/g, "-$1").toLowerCase(); var ret = cs.getPropertyValue(name); - + } else { - + var ret = cs[name]; var style = elem.style; - + // From the awesome hack by Dean Edwards // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - + // If we're not dealing with a regular pixel number // but a number that has a weird ending, we need to convert it to pixels if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { // Remember the original values var left = style.left, rsLeft = elem.runtimeStyle.left; - + // Put in the new values to get a computed value out elem.runtimeStyle.left = cs.left; style.left = ret || 0; ret = style.pixelLeft + "px"; - + // Revert the changed values style.left = left; elem.runtimeStyle.left = rsLeft; } - + } - + // Normalize margin values. This is not totally valid, but in most cases // it is what the user wants to know. if(name.indexOf("margin") > -1 && ret == "auto") { return "0px"; } - + // Some browsers return undefined width and height values as "auto", so // we need to retrieve those ourselves. if (name == "width" && ret == "auto") { @@ -124,13 +125,13 @@ public class ComputedStyle { } else if (name == "height" && ret == "auto") { ret = elem.clientHeight + "px"; } - + return ret; - + }-*/; /** - * Retrieves the given computed property as an integer + * Retrieves the given computed property as an integer. * * Returns 0 if the property cannot be converted to an integer * @@ -147,7 +148,7 @@ public class ComputedStyle { } /** - * Retrieves the given computed property as a double + * Retrieves the given computed property as a double. * * Returns NaN if the property cannot be converted to a double * @@ -165,8 +166,10 @@ public class ComputedStyle { } /** - * Get current margin values from the DOM. The array order is the default - * CSS order: top, right, bottom, left. + * Get current margin values from the DOM. + * + * @return an array containing four values for the four edges, in the + * default CSS order: top, right, bottom, left. */ public final int[] getMargin() { int[] margin = { 0, 0, 0, 0 }; @@ -178,8 +181,10 @@ public class ComputedStyle { } /** - * Get current padding values from the DOM. The array order is the default - * CSS order: top, right, bottom, left. + * Get current padding values from the DOM. + * + * @return an array containing four values for the four edges, in the + * default CSS order: top, right, bottom, left. */ public final int[] getPadding() { int[] padding = { 0, 0, 0, 0 }; @@ -191,8 +196,10 @@ public class ComputedStyle { } /** - * Get current border values from the DOM. The array order is the default - * CSS order: top, right, bottom, left. + * Get current border values from the DOM. + * + * @return an array containing four values for the four edges, in the + * default CSS order: top, right, bottom, left. */ public final int[] getBorder() { int[] border = { 0, 0, 0, 0 }; @@ -226,7 +233,7 @@ public class ComputedStyle { /** * Takes a String value e.g. "12px" and parses that to Integer 12. * - * @param String + * @param value * a value starting with a number * @return Integer the value from the string before any non-numeric * characters. If the value cannot be parsed to a number, returns @@ -282,7 +289,7 @@ public class ComputedStyle { }-*/; /** - * Returns the sum of the top and bottom border width + * Returns the sum of the top and bottom border width. * * @since 7.5.3 * @return the sum of the top and bottom border @@ -295,7 +302,7 @@ public class ComputedStyle { } /** - * Returns the sum of the left and right border width + * Returns the sum of the left and right border width. * * @since 7.5.3 * @return the sum of the left and right border @@ -308,7 +315,7 @@ public class ComputedStyle { } /** - * Returns the sum of the top and bottom padding + * Returns the sum of the top and bottom padding. * * @since 7.5.3 * @return the sum of the top and bottom padding @@ -321,7 +328,7 @@ public class ComputedStyle { } /** - * Returns the sum of the top and bottom padding + * Returns the sum of the top and bottom padding. * * @since 7.5.3 * @return the sum of the left and right padding @@ -334,7 +341,7 @@ public class ComputedStyle { } /** - * Returns the sum of the top and bottom margin + * Returns the sum of the top and bottom margin. * * @since 7.5.6 * @return the sum of the top and bottom margin @@ -347,7 +354,7 @@ public class ComputedStyle { } /** - * Returns the sum of the top and bottom margin + * Returns the sum of the left and right margin. * * @since 7.5.6 * @return the sum of the left and right margin @@ -359,4 +366,46 @@ public class ComputedStyle { return marginWidth; } + /** + * Returns the current height, padding and border from the DOM. + * + * @return the computed height including padding and borders + */ + public double getHeightIncludingBorderPadding() { + double h = getHeight(); + if (BrowserInfo.get().isIE() || isContentBox()) { + // IE11 always returns only the height without padding/border + h += getBorderHeight() + getPaddingHeight(); + } + + return h; + } + + /** + * Returns the current width, padding and border from the DOM. + * + * @return the computed width including padding and borders + */ + public double getWidthIncludingBorderPadding() { + double w = getWidth(); + if (BrowserInfo.get().isIE() || isContentBox()) { + // IE11 always returns only the width without padding/border + w += getBorderWidth() + getPaddingWidth(); + } + return w; + } + + private boolean isContentBox() { + return getBoxSizing().equals(CONTENT_BOX); + } + + /** + * Returns the value of the boxSizing property. + * + * @return the value of the boxSizing property + */ + private String getBoxSizing() { + return getProperty("boxSizing"); + } + } diff --git a/client/src/main/java/com/vaadin/client/widgets/Escalator.java b/client/src/main/java/com/vaadin/client/widgets/Escalator.java index 8f79483eb8..11bfa113cb 100644 --- a/client/src/main/java/com/vaadin/client/widgets/Escalator.java +++ b/client/src/main/java/com/vaadin/client/widgets/Escalator.java @@ -60,6 +60,7 @@ import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.UIObject; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.BrowserInfo; +import com.vaadin.client.ComputedStyle; import com.vaadin.client.DeferredWorker; import com.vaadin.client.Profiler; import com.vaadin.client.WidgetUtil; @@ -701,13 +702,13 @@ public class Escalator extends Widget /*-{ var vScroll = esc.@com.vaadin.client.widgets.Escalator::verticalScrollbar; var vScrollElem = vScroll.@com.vaadin.client.widget.escalator.ScrollbarBundle::getElement()(); - + var hScroll = esc.@com.vaadin.client.widgets.Escalator::horizontalScrollbar; var hScrollElem = hScroll.@com.vaadin.client.widget.escalator.ScrollbarBundle::getElement()(); - + return $entry(function(e) { var target = e.target; - + // in case the scroll event was native (i.e. scrollbars were dragged, or // the scrollTop/Left was manually modified), the bundles have old cache // values. We need to make sure that the caches are kept up to date. @@ -728,29 +729,29 @@ public class Escalator extends Widget return $entry(function(e) { var deltaX = e.deltaX ? e.deltaX : -0.5*e.wheelDeltaX; var deltaY = e.deltaY ? e.deltaY : -0.5*e.wheelDeltaY; - + // Delta mode 0 is in pixels; we don't need to do anything... - + // A delta mode of 1 means we're scrolling by lines instead of pixels // We need to scale the number of lines by the default line height if(e.deltaMode === 1) { var brc = esc.@com.vaadin.client.widgets.Escalator::body; deltaY *= brc.@com.vaadin.client.widgets.Escalator.AbstractRowContainer::getDefaultRowHeight()(); } - + // Other delta modes aren't supported if((e.deltaMode !== undefined) && (e.deltaMode >= 2 || e.deltaMode < 0)) { var msg = "Unsupported wheel delta mode \"" + e.deltaMode + "\""; - + // Print warning message esc.@com.vaadin.client.widgets.Escalator::logWarning(*)(msg); } - + // IE8 has only delta y if (isNaN(deltaY)) { deltaY = -0.5*e.wheelDelta; } - + @com.vaadin.client.widgets.Escalator.JsniUtil::moveScrollFromEvent(*)(esc, deltaX, deltaY, e); }); }-*/; @@ -1054,9 +1055,8 @@ public class Escalator extends Widget + columnConfiguration.getColumnWidthActual(columnIndex); final double viewportStartPx = getScrollLeft(); - double viewportEndPx = viewportStartPx + WidgetUtil - .getRequiredWidthBoundingClientRectDouble(getElement()) - - frozenPixels; + double viewportEndPx = viewportStartPx + + getBoundingWidth(getElement()) - frozenPixels; if (verticalScrollbar.showsScrollHandle()) { viewportEndPx -= WidgetUtil.getNativeScrollbarSize(); } @@ -1744,8 +1744,7 @@ public class Escalator extends Widget final boolean isVisible = !cell.getStyle().getDisplay() .equals(Display.NONE.getCssName()); if (isVisible) { - maxWidth = Math.max(maxWidth, WidgetUtil - .getRequiredWidthBoundingClientRectDouble(cell)); + maxWidth = Math.max(maxWidth, getBoundingWidth(cell)); } row = TableRowElement.as(row.getNextSiblingElement()); } @@ -1982,8 +1981,7 @@ public class Escalator extends Widget detectionTr.appendChild(cellElem); root.appendChild(detectionTr); - double boundingHeight = WidgetUtil - .getRequiredHeightBoundingClientRectDouble(cellElem); + double boundingHeight = getBoundingHeight(cellElem); defaultRowHeight = Math.max(1.0d, boundingHeight); root.removeChild(detectionTr); @@ -2059,8 +2057,7 @@ public class Escalator extends Widget cellClone.getStyle().clearWidth(); cell.getParentElement().insertBefore(cellClone, cell); - double requiredWidth = WidgetUtil - .getRequiredWidthBoundingClientRectDouble(cellClone); + double requiredWidth = getBoundingWidth(cellClone); if (BrowserInfo.get().isIE()) { /* * IE browsers have some issues with subpixels. Occasionally @@ -5279,9 +5276,7 @@ public class Escalator extends Widget if (spacerDecoContainer.getParentElement() == null) { getElement().appendChild(spacerDecoContainer); // calculate the spacer deco width, it won't change - spacerDecoWidth = WidgetUtil - .getRequiredWidthBoundingClientRectDouble( - spacer.getDecoElement()); + spacerDecoWidth = getBoundingWidth(spacer.getDecoElement()); } initSpacerContent(spacer); @@ -5682,6 +5677,19 @@ public class Escalator extends Widget publishJSHelpers(root); } + private double getBoundingWidth(Element element) { + // Gets the current width, including border and padding, for the element + // while ignoring any transforms applied to the element (e.g. scale) + return new ComputedStyle(element).getWidthIncludingBorderPadding(); + } + + private double getBoundingHeight(Element element) { + // Gets the current height, including border and padding, for the + // element while ignoring any transforms applied to the element (e.g. + // scale) + return new ComputedStyle(element).getHeightIncludingBorderPadding(); + } + private int getBodyRowCount() { return getBody().getRowCount(); } @@ -6292,10 +6300,8 @@ public class Escalator extends Widget } Profiler.enter("Escalator.recalculateElementSizes"); - widthOfEscalator = Math.max(0, WidgetUtil - .getRequiredWidthBoundingClientRectDouble(getElement())); - heightOfEscalator = Math.max(0, WidgetUtil - .getRequiredHeightBoundingClientRectDouble(getElement())); + widthOfEscalator = Math.max(0, getBoundingWidth(getElement())); + heightOfEscalator = Math.max(0, getBoundingHeight(getElement())); header.recalculateSectionHeight(); body.recalculateSectionHeight(); @@ -6662,8 +6668,7 @@ public class Escalator extends Widget * @return escalator's inner width */ public double getInnerWidth() { - return WidgetUtil - .getRequiredWidthBoundingClientRectDouble(tableWrapper); + return getBoundingWidth(tableWrapper); } /** |