Skip to content

Commit

Permalink
fix(overlay): disable pointer events if overlay is detached (#2747)
Browse files Browse the repository at this point in the history
Fixes #2739
  • Loading branch information
devversion authored and kara committed Feb 2, 2017
1 parent f63eb43 commit 453fa7f
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 1 deletion.
11 changes: 11 additions & 0 deletions src/lib/core/overlay/overlay-directives.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,25 @@ describe('Overlay directives', () => {
fixture.detectChanges();
});

/** Returns the current open overlay pane element. */
function getPaneElement() {
return overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement;
}

it(`should attach the overlay based on the open property`, () => {
fixture.componentInstance.isOpen = true;
fixture.detectChanges();

expect(overlayContainerElement.textContent).toContain('Menu content');
expect(getPaneElement().style.pointerEvents)
.toBeFalsy('Expected the overlay pane to enable pointerEvents when attached.');

fixture.componentInstance.isOpen = false;
fixture.detectChanges();

expect(overlayContainerElement.textContent).toBe('');
expect(getPaneElement().style.pointerEvents)
.toBe('none', 'Expected the overlay pane to disable pointerEvents when detached.');
});

it('should destroy the overlay when the directive is destroyed', () => {
Expand All @@ -47,6 +56,8 @@ describe('Overlay directives', () => {
fixture.destroy();

expect(overlayContainerElement.textContent.trim()).toBe('');
expect(getPaneElement())
.toBeFalsy('Expected the overlay pane element to be removed when disposed.');
});

it('should use a connected position strategy with a default set of positions', () => {
Expand Down
16 changes: 16 additions & 0 deletions src/lib/core/overlay/overlay-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,15 @@ export class OverlayRef implements PortalHost {
}

let attachResult = this._portalHost.attach(portal);

// Update the pane element with the given state configuration.
this.updateSize();
this.updateDirection();
this.updatePosition();

// Enable pointer events for the overlay pane element.
this._togglePointerEvents(true);

return attachResult;
}

Expand All @@ -48,6 +53,12 @@ export class OverlayRef implements PortalHost {
*/
detach(): Promise<any> {
this._detachBackdrop();

// When the overlay is detached, the pane element should disable pointer events.
// This is necessary because otherwise the pane element will cover the page and disable
// pointer events therefore. Depends on the position strategy and the applied pane boundaries.
this._togglePointerEvents(false);

return this._portalHost.detach();
}

Expand Down Expand Up @@ -115,6 +126,11 @@ export class OverlayRef implements PortalHost {
}
}

/** Toggles the pointer events for the overlay pane element. */
private _togglePointerEvents(enablePointer: boolean) {
this._pane.style.pointerEvents = enablePointer ? null : 'none';
}

/** Attaches a backdrop for this overlay. */
private _attachBackdrop() {
this._backdropElement = document.createElement('div');
Expand Down
17 changes: 17 additions & 0 deletions src/lib/core/overlay/overlay.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,23 @@ describe('Overlay', () => {
expect(overlayContainerElement.textContent).toBe('');
});

it('should disable pointer events of the pane element if detached', () => {
let overlayRef = overlay.create();
let paneElement = overlayRef.overlayElement;

overlayRef.attach(componentPortal);

expect(paneElement.childNodes.length).not.toBe(0);
expect(paneElement.style.pointerEvents)
.toBeFalsy('Expected the overlay pane to enable pointerEvents when attached.');

overlayRef.detach();

expect(paneElement.childNodes.length).toBe(0);
expect(paneElement.style.pointerEvents)
.toBe('none', 'Expected the overlay pane to disable pointerEvents when detached.');
});

it('should open multiple overlays', () => {
let pizzaOverlayRef = overlay.create();
pizzaOverlayRef.attach(componentPortal);
Expand Down
5 changes: 4 additions & 1 deletion src/lib/core/portal/dom-portal-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,14 @@ export class DomPortalHost extends BasePortalHost {
let viewContainer = portal.viewContainerRef;
let viewRef = viewContainer.createEmbeddedView(portal.templateRef);

// The method `createEmbeddedView` will add the view as a child of the viewContainer.
// But for the DomPortalHost the view can be added everywhere in the DOM (e.g Overlay Container)
// To move the view to the specified host element. We just re-append the existing root nodes.
viewRef.rootNodes.forEach(rootNode => this._hostDomElement.appendChild(rootNode));

this.setDisposeFn((() => {
let index = viewContainer.indexOf(viewRef);
if (index != -1) {
if (index !== -1) {
viewContainer.remove(index);
}
}));
Expand Down

0 comments on commit 453fa7f

Please sign in to comment.