mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(overlay): add scroll blocking strategy (#4500)
Adds the `BlockScrollStrategy` which, when activated, will prevent the user from scrolling. For now it is only used in the dialog. Relates to #4093.
This commit is contained in:
committed by
Jeremy Elbourn
parent
0666207527
commit
6842046979
@@ -0,0 +1,134 @@
|
||||
import {browser, Key, element, by} from 'protractor';
|
||||
import {screenshot} from '../../screenshot';
|
||||
import {getScrollPosition} from '../../util/query';
|
||||
|
||||
|
||||
describe('scroll blocking', () => {
|
||||
beforeEach(() => browser.get('/block-scroll-strategy'));
|
||||
afterEach(() => clickOn('disable'));
|
||||
|
||||
it('should not be able to scroll programmatically along the x axis', async (done) => {
|
||||
scrollPage(0, 100);
|
||||
expect((await getScrollPosition()).y).toBe(100, 'Expected the page to be scrollable.');
|
||||
|
||||
clickOn('enable');
|
||||
scrollPage(0, 200);
|
||||
expect((await getScrollPosition()).y).toBe(100, 'Expected the page not to be scrollable.');
|
||||
|
||||
clickOn('disable');
|
||||
scrollPage(0, 300);
|
||||
expect((await getScrollPosition()).y).toBe(300, 'Exected page to be scrollable again.');
|
||||
|
||||
screenshot();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should not be able to scroll programmatically along the y axis', async (done) => {
|
||||
scrollPage(100, 0);
|
||||
expect((await getScrollPosition()).x).toBe(100, 'Expected the page to be scrollable.');
|
||||
|
||||
clickOn('enable');
|
||||
scrollPage(200, 0);
|
||||
expect((await getScrollPosition()).x).toBe(100, 'Expected the page not to be scrollable.');
|
||||
|
||||
clickOn('disable');
|
||||
scrollPage(300, 0);
|
||||
expect((await getScrollPosition()).x).toBe(300, 'Exected page to be scrollable again.');
|
||||
|
||||
screenshot();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should not be able to scroll via the keyboard along the y axis', async (done) => {
|
||||
const body = element(by.tagName('body'));
|
||||
|
||||
scrollPage(0, 100);
|
||||
expect((await getScrollPosition()).y).toBe(100, 'Expected the page to be scrollable.');
|
||||
|
||||
clickOn('enable');
|
||||
await body.sendKeys(Key.ARROW_DOWN);
|
||||
await body.sendKeys(Key.ARROW_DOWN);
|
||||
await body.sendKeys(Key.ARROW_DOWN);
|
||||
expect((await getScrollPosition()).y).toBe(100, 'Expected the page not to be scrollable.');
|
||||
|
||||
clickOn('disable');
|
||||
await body.sendKeys(Key.ARROW_DOWN);
|
||||
await body.sendKeys(Key.ARROW_DOWN);
|
||||
await body.sendKeys(Key.ARROW_DOWN);
|
||||
expect((await getScrollPosition()).y)
|
||||
.toBeGreaterThan(100, 'Expected the page to be scrollable again.');
|
||||
|
||||
screenshot();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should not be able to scroll via the keyboard along the x axis', async (done) => {
|
||||
const body = element(by.tagName('body'));
|
||||
|
||||
scrollPage(100, 0);
|
||||
expect((await getScrollPosition()).x).toBe(100, 'Expected the page to be scrollable.');
|
||||
|
||||
clickOn('enable');
|
||||
await body.sendKeys(Key.ARROW_RIGHT);
|
||||
await body.sendKeys(Key.ARROW_RIGHT);
|
||||
await body.sendKeys(Key.ARROW_RIGHT);
|
||||
expect((await getScrollPosition()).x).toBe(100, 'Expected the page not to be scrollable.');
|
||||
|
||||
clickOn('disable');
|
||||
await body.sendKeys(Key.ARROW_RIGHT);
|
||||
await body.sendKeys(Key.ARROW_RIGHT);
|
||||
await body.sendKeys(Key.ARROW_RIGHT);
|
||||
expect((await getScrollPosition()).x)
|
||||
.toBeGreaterThan(100, 'Expected the page to be scrollable again.');
|
||||
|
||||
screenshot();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should not be able to scroll the page after reaching the end of an element along the y axis',
|
||||
async (done) => {
|
||||
const scroller = element(by.id('scroller'));
|
||||
|
||||
browser.executeScript(`document.getElementById('scroller').scrollTop = 200;`);
|
||||
scrollPage(0, 100);
|
||||
expect((await getScrollPosition()).y).toBe(100, 'Expected the page to be scrollable.');
|
||||
|
||||
clickOn('enable');
|
||||
scroller.sendKeys(Key.ARROW_DOWN);
|
||||
scroller.sendKeys(Key.ARROW_DOWN);
|
||||
scroller.sendKeys(Key.ARROW_DOWN);
|
||||
expect((await getScrollPosition()).y).toBe(100, 'Expected the page not to have scrolled.');
|
||||
|
||||
screenshot();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should not be able to scroll the page after reaching the end of an element along the x axis',
|
||||
async (done) => {
|
||||
const scroller = element(by.id('scroller'));
|
||||
|
||||
browser.executeScript(`document.getElementById('scroller').scrollLeft = 200;`);
|
||||
scrollPage(100, 0);
|
||||
expect((await getScrollPosition()).x).toBe(100, 'Expected the page to be scrollable.');
|
||||
|
||||
clickOn('enable');
|
||||
scroller.sendKeys(Key.ARROW_RIGHT);
|
||||
scroller.sendKeys(Key.ARROW_RIGHT);
|
||||
scroller.sendKeys(Key.ARROW_RIGHT);
|
||||
expect((await getScrollPosition()).x).toBe(100, 'Expected the page not to have scrolled.');
|
||||
|
||||
screenshot();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
// Clicks on a button programmatically. Note that we can't use Protractor's `.click`, because
|
||||
// it performs a real click, which will scroll the button into view.
|
||||
function clickOn(id: string) {
|
||||
browser.executeScript(`document.getElementById('${id}').click()`);
|
||||
}
|
||||
|
||||
// Scrolls the page to the specified coordinates.
|
||||
function scrollPage(x: number, y: number) {
|
||||
return browser.executeScript(`window.scrollTo(${x}, ${y});`);
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"inlineSources": true,
|
||||
"lib": ["es2015"],
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"noEmitOnError": true,
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ export function expectFocusOn(element: FinderResult, expected = true): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that an element has a certan location.
|
||||
* Asserts that an element has a certain location.
|
||||
*/
|
||||
export function expectLocation(element: FinderResult, {x, y}: Point): void {
|
||||
getElement(element).getLocation().then((location: Point) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {ElementFinder, by, element, ProtractorBy, browser} from 'protractor';
|
||||
import {Point} from './actions';
|
||||
|
||||
/**
|
||||
* Normalizes either turning a selector into an
|
||||
@@ -15,4 +16,21 @@ export function waitForElement(selector: string) {
|
||||
return browser.isElementPresent(by.css(selector) as ProtractorBy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the current scroll position of the page.
|
||||
*/
|
||||
export async function getScrollPosition(): Promise<Point> {
|
||||
const snippet = `
|
||||
var documentRect = document.documentElement.getBoundingClientRect();
|
||||
var x = -documentRect.left || document.body.scrollLeft || window.scrollX ||
|
||||
document.documentElement.scrollLeft || 0;
|
||||
var y = -documentRect.top || document.body.scrollTop || window.scrollY ||
|
||||
document.documentElement.scrollTop || 0;
|
||||
|
||||
return {x: x, y: y};
|
||||
`;
|
||||
|
||||
return await browser.executeScript<Point>(snippet);
|
||||
}
|
||||
|
||||
export type FinderResult = ElementFinder | string;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
.spacer {
|
||||
background: #3f51b5;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.spacer.vertical {
|
||||
width: 100px;
|
||||
height: 3000px;
|
||||
}
|
||||
|
||||
.spacer.horizontal {
|
||||
width: 3000px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
overflow: auto;
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 200px;
|
||||
}
|
||||
|
||||
.scroller-spacer {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: #ff4081;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<p>
|
||||
<button id="enable" (click)="scrollStrategy.enable()">Enable scroll blocking</button>
|
||||
<button id="disable" (click)="scrollStrategy.disable()">Disable scroll blocking</button>
|
||||
</p>
|
||||
<div class="spacer vertical"></div>
|
||||
<!-- this one needs a tabindex so protractor can trigger key presses inside it -->
|
||||
<div class="scroller" id="scroller" tabindex="-1">
|
||||
<div class="scroller-spacer"></div>
|
||||
</div>
|
||||
<div class="spacer horizontal"></div>
|
||||
@@ -0,0 +1,13 @@
|
||||
import {Component} from '@angular/core';
|
||||
import {BlockScrollStrategy, ViewportRuler} from '@angular/material';
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'block-scroll-strategy-e2e',
|
||||
templateUrl: 'block-scroll-strategy-e2e.html',
|
||||
styleUrls: ['block-scroll-strategy-e2e.css'],
|
||||
})
|
||||
export class BlockScrollStrategyE2E {
|
||||
constructor(private _viewportRuler: ViewportRuler) { }
|
||||
scrollStrategy = new BlockScrollStrategy(this._viewportRuler);
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import {MaterialModule, OverlayContainer, FullscreenOverlayContainer} from '@ang
|
||||
import {E2E_APP_ROUTES} from './e2e-app/routes';
|
||||
import {SlideToggleE2E} from './slide-toggle/slide-toggle-e2e';
|
||||
import {InputE2E} from './input/input-e2e';
|
||||
import {BlockScrollStrategyE2E} from './block-scroll-strategy/block-scroll-strategy-e2e';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -45,7 +46,8 @@ import {InputE2E} from './input/input-e2e';
|
||||
SimpleRadioButtons,
|
||||
SlideToggleE2E,
|
||||
TestDialog,
|
||||
TestDialogFullScreen
|
||||
TestDialogFullScreen,
|
||||
BlockScrollStrategyE2E
|
||||
],
|
||||
bootstrap: [E2EApp],
|
||||
providers: [
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<button (click)="showLinks = !showLinks">Toggle Navigation Links</button>
|
||||
|
||||
<md-nav-list *ngIf="showLinks">
|
||||
<a md-list-item [routerLink]="['block-scroll-strategy']">Block scroll strategy</a>
|
||||
<a md-list-item [routerLink]="['button']">Button</a>
|
||||
<a md-list-item [routerLink]="['checkbox']">Checkbox</a>
|
||||
<a md-list-item [routerLink]="['dialog']">Dialog</a>
|
||||
|
||||
@@ -14,9 +14,11 @@ import {ProgressSpinnerE2E} from '../progress-spinner/progress-spinner-e2e';
|
||||
import {SlideToggleE2E} from '../slide-toggle/slide-toggle-e2e';
|
||||
import {FullscreenE2E} from '../fullscreen/fullscreen-e2e';
|
||||
import {InputE2E} from '../input/input-e2e';
|
||||
import {BlockScrollStrategyE2E} from '../block-scroll-strategy/block-scroll-strategy-e2e';
|
||||
|
||||
export const E2E_APP_ROUTES: Routes = [
|
||||
{path: '', component: Home},
|
||||
{path: 'block-scroll-strategy', component: BlockScrollStrategyE2E},
|
||||
{path: 'button', component: ButtonE2E},
|
||||
{path: 'checkbox', component: SimpleCheckboxes},
|
||||
{path: 'dialog', component: DialogE2E},
|
||||
|
||||
@@ -67,4 +67,17 @@
|
||||
.cdk-overlay-transparent-backdrop {
|
||||
background: none;
|
||||
}
|
||||
|
||||
// Used when disabling global scrolling.
|
||||
.cdk-global-scrollblock {
|
||||
position: fixed;
|
||||
|
||||
// Necessary for iOS not to expand past the viewport.
|
||||
max-width: 100vw;
|
||||
|
||||
// Note: this will always add a scrollbar to whatever element it is on, which can
|
||||
// potentially result in double scrollbars. It shouldn't be an issue, because we won't
|
||||
// block scrolling on a page that doesn't have a scrollbar in the first place.
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ export {OverlayRef} from './overlay-ref';
|
||||
export {OverlayState} from './overlay-state';
|
||||
export {ConnectedOverlayDirective, OverlayOrigin, OverlayModule} from './overlay-directives';
|
||||
export {ScrollDispatcher} from './scroll/scroll-dispatcher';
|
||||
export {ViewportRuler} from './position/viewport-ruler';
|
||||
|
||||
export * from './position/connected-position';
|
||||
|
||||
@@ -18,3 +19,4 @@ export {ScrollStrategy} from './scroll/scroll-strategy';
|
||||
export {RepositionScrollStrategy} from './scroll/reposition-scroll-strategy';
|
||||
export {CloseScrollStrategy} from './scroll/close-scroll-strategy';
|
||||
export {NoopScrollStrategy} from './scroll/noop-scroll-strategy';
|
||||
export {BlockScrollStrategy} from './scroll/block-scroll-strategy';
|
||||
|
||||
@@ -66,8 +66,11 @@ export class ViewportRuler {
|
||||
// `scrollTop` and `scrollLeft` is inconsistent. However, using the bounding rect of
|
||||
// `document.documentElement` works consistently, where the `top` and `left` values will
|
||||
// equal negative the scroll position.
|
||||
const top = -documentRect.top || document.body.scrollTop || window.scrollY || 0;
|
||||
const left = -documentRect.left || document.body.scrollLeft || window.scrollX || 0;
|
||||
const top = -documentRect.top || document.body.scrollTop || window.scrollY ||
|
||||
document.documentElement.scrollTop || 0;
|
||||
|
||||
const left = -documentRect.left || document.body.scrollLeft || window.scrollX ||
|
||||
document.documentElement.scrollLeft || 0;
|
||||
|
||||
return {top, left};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
import {inject, TestBed, async} from '@angular/core/testing';
|
||||
import {ComponentPortal, OverlayModule, BlockScrollStrategy, Platform} from '../../core';
|
||||
import {ViewportRuler} from '../position/viewport-ruler';
|
||||
|
||||
|
||||
describe('BlockScrollStrategy', () => {
|
||||
let platform = new Platform();
|
||||
let strategy: BlockScrollStrategy;
|
||||
let viewport: ViewportRuler;
|
||||
let forceScrollElement: HTMLElement;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({imports: [OverlayModule]}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(inject([ViewportRuler], (viewportRuler: ViewportRuler) => {
|
||||
strategy = new BlockScrollStrategy(viewportRuler);
|
||||
viewport = viewportRuler;
|
||||
forceScrollElement = document.createElement('div');
|
||||
document.body.appendChild(forceScrollElement);
|
||||
forceScrollElement.style.width = '100px';
|
||||
forceScrollElement.style.height = '3000px';
|
||||
}));
|
||||
|
||||
afterEach(() => {
|
||||
document.body.removeChild(forceScrollElement);
|
||||
setScrollPosition(0, 0);
|
||||
});
|
||||
|
||||
it('should toggle scroll blocking along the y axis', skipIOS(() => {
|
||||
setScrollPosition(0, 100);
|
||||
expect(viewport.getViewportScrollPosition().top)
|
||||
.toBe(100, 'Expected viewport to be scrollable initially.');
|
||||
|
||||
strategy.enable();
|
||||
expect(document.documentElement.style.top)
|
||||
.toBe('-100px', 'Expected <html> element to be offset by the previous scroll amount.');
|
||||
|
||||
setScrollPosition(0, 300);
|
||||
expect(viewport.getViewportScrollPosition().top)
|
||||
.toBe(100, 'Expected the viewport not to scroll.');
|
||||
|
||||
strategy.disable();
|
||||
expect(viewport.getViewportScrollPosition().top)
|
||||
.toBe(100, 'Expected old scroll position to have bee restored after disabling.');
|
||||
|
||||
setScrollPosition(0, 300);
|
||||
expect(viewport.getViewportScrollPosition().top)
|
||||
.toBe(300, 'Expected user to be able to scroll after disabling.');
|
||||
}));
|
||||
|
||||
|
||||
it('should toggle scroll blocking along the x axis', skipIOS(() => {
|
||||
forceScrollElement.style.height = '100px';
|
||||
forceScrollElement.style.width = '3000px';
|
||||
|
||||
setScrollPosition(100, 0);
|
||||
expect(viewport.getViewportScrollPosition().left)
|
||||
.toBe(100, 'Expected viewport to be scrollable initially.');
|
||||
|
||||
strategy.enable();
|
||||
expect(document.documentElement.style.left)
|
||||
.toBe('-100px', 'Expected <html> element to be offset by the previous scroll amount.');
|
||||
|
||||
setScrollPosition(300, 0);
|
||||
expect(viewport.getViewportScrollPosition().left)
|
||||
.toBe(100, 'Expected the viewport not to scroll.');
|
||||
|
||||
strategy.disable();
|
||||
expect(viewport.getViewportScrollPosition().left)
|
||||
.toBe(100, 'Expected old scroll position to have bee restored after disabling.');
|
||||
|
||||
setScrollPosition(300, 0);
|
||||
expect(viewport.getViewportScrollPosition().left)
|
||||
.toBe(300, 'Expected user to be able to scroll after disabling.');
|
||||
}));
|
||||
|
||||
|
||||
it('should toggle the `cdk-global-scrollblock` class', skipIOS(() => {
|
||||
expect(document.documentElement.classList).not.toContain('cdk-global-scrollblock');
|
||||
|
||||
strategy.enable();
|
||||
expect(document.documentElement.classList).toContain('cdk-global-scrollblock');
|
||||
|
||||
strategy.disable();
|
||||
expect(document.documentElement.classList).not.toContain('cdk-global-scrollblock');
|
||||
}));
|
||||
|
||||
it('should restore any previously-set inline styles', skipIOS(() => {
|
||||
const root = document.documentElement;
|
||||
|
||||
root.style.top = '13px';
|
||||
root.style.left = '37px';
|
||||
|
||||
strategy.enable();
|
||||
|
||||
expect(root.style.top).not.toBe('13px');
|
||||
expect(root.style.left).not.toBe('37px');
|
||||
|
||||
strategy.disable();
|
||||
|
||||
expect(root.style.top).toBe('13px');
|
||||
expect(root.style.left).toBe('37px');
|
||||
}));
|
||||
|
||||
it(`should't do anything if the page isn't scrollable`, skipIOS(() => {
|
||||
forceScrollElement.style.display = 'none';
|
||||
strategy.enable();
|
||||
expect(document.documentElement.classList).not.toContain('cdk-global-scrollblock');
|
||||
}));
|
||||
|
||||
|
||||
/**
|
||||
* Skips the specified test, if it is being executed on iOS. This is necessary, because
|
||||
* programmatic scrolling inside the Karma iframe doesn't work on iOS, which renders these
|
||||
* tests unusable. For example, something as basic as the following won't work:
|
||||
* ```
|
||||
* window.scroll(0, 100);
|
||||
* viewport._cacheViewportGeometry();
|
||||
* expect(viewport.getViewportScrollPosition().top).toBe(100);
|
||||
* ```
|
||||
* @param spec Test to be executed or skipped.
|
||||
*/
|
||||
function skipIOS(spec: Function) {
|
||||
return () => {
|
||||
if (!platform.IOS) {
|
||||
spec();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the viewport and clears the cache.
|
||||
* @param x Amount to scroll along the x axis.
|
||||
* @param y Amount to scroll along the y axis.
|
||||
*/
|
||||
function setScrollPosition(x: number, y: number) {
|
||||
window.scroll(x, y);
|
||||
viewport._cacheViewportGeometry();
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
import {ScrollStrategy} from './scroll-strategy';
|
||||
import {ViewportRuler} from '../position/viewport-ruler';
|
||||
|
||||
/**
|
||||
* Strategy that will prevent the user from scrolling while the overlay is visible.
|
||||
*/
|
||||
export class BlockScrollStrategy implements ScrollStrategy {
|
||||
private _previousHTMLStyles = { top: null, left: null };
|
||||
private _previousScrollPosition: { top: number, left: number };
|
||||
private _isEnabled = false;
|
||||
|
||||
constructor(private _viewportRuler: ViewportRuler) { }
|
||||
|
||||
attach() { }
|
||||
|
||||
enable() {
|
||||
if (this._canBeEnabled()) {
|
||||
const root = document.documentElement;
|
||||
|
||||
this._previousScrollPosition = this._viewportRuler.getViewportScrollPosition();
|
||||
|
||||
// Cache the previous inline styles in case the user had set them.
|
||||
this._previousHTMLStyles.left = root.style.left;
|
||||
this._previousHTMLStyles.top = root.style.top;
|
||||
|
||||
// Note: we're using the `html` node, instead of the `body`, because the `body` may
|
||||
// have the user agent margin, whereas the `html` is guaranteed not to have one.
|
||||
root.style.left = `${-this._previousScrollPosition.left}px`;
|
||||
root.style.top = `${-this._previousScrollPosition.top}px`;
|
||||
root.classList.add('cdk-global-scrollblock');
|
||||
this._isEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
disable() {
|
||||
if (this._isEnabled) {
|
||||
this._isEnabled = false;
|
||||
document.documentElement.style.left = this._previousHTMLStyles.left;
|
||||
document.documentElement.style.top = this._previousHTMLStyles.top;
|
||||
document.documentElement.classList.remove('cdk-global-scrollblock');
|
||||
window.scroll(this._previousScrollPosition.left, this._previousScrollPosition.top);
|
||||
}
|
||||
}
|
||||
|
||||
private _canBeEnabled(): boolean {
|
||||
// Since the scroll strategies can't be singletons, we have to use a global CSS class
|
||||
// (`cdk-global-scrollblock`) to make sure that we don't try to disable global
|
||||
// scrolling multiple times.
|
||||
if (document.documentElement.classList.contains('cdk-global-scrollblock') || this._isEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const body = document.body;
|
||||
const viewport = this._viewportRuler.getViewportRect();
|
||||
return body.scrollHeight > viewport.height || body.scrollWidth > viewport.width;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,8 @@ import {MdDialogConfig} from './dialog-config';
|
||||
import {MdDialogRef} from './dialog-ref';
|
||||
import {MdDialogContainer} from './dialog-container';
|
||||
import {TemplatePortal} from '../core/portal/portal';
|
||||
import {BlockScrollStrategy} from '../core/overlay/scroll/block-scroll-strategy';
|
||||
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
|
||||
import 'rxjs/add/operator/first';
|
||||
|
||||
|
||||
@@ -48,6 +50,7 @@ export class MdDialog {
|
||||
constructor(
|
||||
private _overlay: Overlay,
|
||||
private _injector: Injector,
|
||||
private _viewportRuler: ViewportRuler,
|
||||
@Optional() private _location: Location,
|
||||
@Optional() @SkipSelf() private _parentDialog: MdDialog) {
|
||||
|
||||
@@ -119,6 +122,7 @@ export class MdDialog {
|
||||
private _getOverlayState(dialogConfig: MdDialogConfig): OverlayState {
|
||||
let overlayState = new OverlayState();
|
||||
overlayState.hasBackdrop = dialogConfig.hasBackdrop;
|
||||
overlayState.scrollStrategy = new BlockScrollStrategy(this._viewportRuler);
|
||||
if (dialogConfig.backdropClass) {
|
||||
overlayState.backdropClass = dialogConfig.backdropClass;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user