From cb7b30d5283e98e8166a52c084e3070159a17892 Mon Sep 17 00:00:00 2001 From: crisbeto Date: Sat, 8 Jun 2019 16:27:34 +0200 Subject: [PATCH] fix(overlay): incorrectly calculating position when page is scrolled horizontally and overlay is anchored to the right Fixes the flexible connected position strategy calculating where to position the panel incorrectly if it's anchored so that its content flows to the left and the page is scrolled horizontally. Furthermore, the calculations for the bounding box width weren't correct for this case either. Fixes #16009. --- ...exible-connected-position-strategy.spec.ts | 76 +++++++++++++++++++ .../flexible-connected-position-strategy.ts | 4 +- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts b/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts index a60d03642088..4609aaad4349 100644 --- a/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts +++ b/src/cdk/overlay/position/flexible-connected-position-strategy.spec.ts @@ -1927,6 +1927,82 @@ describe('FlexibleConnectedPositionStrategy', () => { expect(Math.floor(overlayRect.bottom)).toBe(Math.floor(originRect.bottom)); }); + it('should position an overlay that is flowing to the left correctly on a page that is ' + + 'scrolled horizontally', () => { + const veryLargeElement: HTMLElement = document.createElement('div'); + veryLargeElement.style.width = '4000px'; + veryLargeElement.style.height = '4000px'; + document.body.appendChild(veryLargeElement); + window.scroll(2100, 0); + + originElement.style.position = 'absolute'; + originElement.style.top = '100px'; + originElement.style.left = '300px'; + + positionStrategy + .withFlexibleDimensions() + .withPush(false) + .withPositions([{ + overlayY: 'top', + overlayX: 'end', + originY: 'top', + originX: 'end' + }]); + + attachOverlay({positionStrategy}); + + const originRect = originElement.getBoundingClientRect(); + const overlayRect = overlayRef.overlayElement.getBoundingClientRect(); + + expect(Math.floor(overlayRect.right)).toBe(Math.floor(originRect.right)); + expect(Math.floor(overlayRect.top)).toBe(Math.floor(originRect.top)); + + window.scroll(0, 0); + document.body.removeChild(veryLargeElement); + }); + + it('should size the bounding box that is flowing to the left correctly on a page that is ' + + 'scrolled horizontally', () => { + const veryLargeElement: HTMLElement = document.createElement('div'); + veryLargeElement.style.width = '4000px'; + veryLargeElement.style.height = '4000px'; + document.body.appendChild(veryLargeElement); + window.scroll(100, 0); + + originElement.style.position = 'absolute'; + originElement.style.top = '100px'; + originElement.style.left = '300px'; + + positionStrategy + .withFlexibleDimensions() + .withPush(false) + .withPositions([{ + overlayY: 'top', + overlayX: 'end', + originY: 'top', + originX: 'end' + }]); + + attachOverlay({positionStrategy}); + + let originRect = originElement.getBoundingClientRect(); + let boundingBoxRect = overlayRef.hostElement.getBoundingClientRect(); + + expect(Math.floor(originRect.right)).toBe(Math.floor(boundingBoxRect.width)); + + window.scroll(200, 0); + overlayRef.updatePosition(); + + originRect = originElement.getBoundingClientRect(); + boundingBoxRect = overlayRef.hostElement.getBoundingClientRect(); + + expect(Math.floor(originRect.right)).toBe(Math.floor(boundingBoxRect.width)); + + window.scroll(0, 0); + document.body.removeChild(veryLargeElement); + }); + + }); describe('onPositionChange with scrollable view properties', () => { diff --git a/src/cdk/overlay/position/flexible-connected-position-strategy.ts b/src/cdk/overlay/position/flexible-connected-position-strategy.ts index 5ffae629a00f..d213cf9af07d 100644 --- a/src/cdk/overlay/position/flexible-connected-position-strategy.ts +++ b/src/cdk/overlay/position/flexible-connected-position-strategy.ts @@ -741,8 +741,8 @@ export class FlexibleConnectedPositionStrategy implements PositionStrategy { let width: number, left: number, right: number; if (isBoundedByLeftViewportEdge) { - right = viewport.right - origin.x + this._viewportMargin; - width = origin.x - viewport.left; + right = viewport.width - origin.x + this._viewportMargin; + width = origin.x - this._viewportMargin; } else if (isBoundedByRightViewportEdge) { left = origin.x; width = viewport.right - origin.x;