diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 21ff9fd082ec..9cc8781250ec 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -156,7 +156,6 @@ /e2e/components/checkbox-e2e.spec.ts @jelbourn @devversion /e2e/components/dialog-e2e.spec.ts @jelbourn @crisbeto /e2e/components/expansion-e2e.spec.ts @josephperrott @jelbourn -/e2e/components/fullscreen-e2e.spec.ts @jelbourn /e2e/components/grid-list-e2e.spec.ts @jelbourn /e2e/components/icon-e2e.spec.ts @jelbourn /e2e/components/input-e2e.spec.ts @mmalerba @@ -178,7 +177,6 @@ /src/e2e-app/checkbox/** @jelbourn @devversion /src/e2e-app/dialog/** @jelbourn @crisbeto /src/e2e-app/e2e-app/** @jelbourn -/src/e2e-app/fullscreen/** @jelbourn /src/e2e-app/grid-list/** @jelbourn /src/e2e-app/icon/** @jelbourn /src/e2e-app/input/** @mmalerba diff --git a/e2e/components/fullscreen-e2e.spec.ts b/e2e/components/fullscreen-e2e.spec.ts deleted file mode 100644 index 4404f484537b..000000000000 --- a/e2e/components/fullscreen-e2e.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {browser, by, element} from 'protractor'; - -describe('fullscreen', () => { - - beforeEach(() => browser.get('/fullscreen')); - - it('should open a dialog inside a fullscreen element and move it to the body', async () => { - element(by.id('fullscreen-open')).click(); - element(by.id('dialog-open')).click(); - - await expectOverlayInFullscreen(); - - element(by.id('dialog-fullscreen-exit')).click(); - await expectOverlayInBody(); - }); - - it('should open a dialog inside the body and move it to a fullscreen element', async () => { - element(by.id('dialog-open')).click(); - await expectOverlayInBody(); - - element(by.id('dialog-fullscreen-open')).click(); - await expectOverlayInFullscreen(); - - element(by.id('dialog-fullscreen-exit')).click(); - await expectOverlayInBody(); - }); - - /** Expects the overlay container to be inside of the body element. */ - async function expectOverlayInBody() { - expect(await browser.isElementPresent(by.css('body > .cdk-overlay-container'))) - .toBe(true, 'Expected the overlay container to be inside of the body.'); - } - - /** Expects the overlay container to be in fullscreen mode. */ - async function expectOverlayInFullscreen() { - expect(await browser.isElementPresent(by.css('#fullscreen-pane > .cdk-overlay-container'))) - .toBe(true, 'Expected the overlay container to be in fullscreen mode.'); - } - -}); diff --git a/src/cdk/overlay/fullscreen-overlay-container.spec.ts b/src/cdk/overlay/fullscreen-overlay-container.spec.ts new file mode 100644 index 000000000000..6978455ff12c --- /dev/null +++ b/src/cdk/overlay/fullscreen-overlay-container.spec.ts @@ -0,0 +1,127 @@ +import {async, inject, TestBed} from '@angular/core/testing'; +import {Component, NgModule, ViewChild, ViewContainerRef} from '@angular/core'; +import {PortalModule, CdkPortal} from '@angular/cdk/portal'; +import {DOCUMENT} from '@angular/platform-browser'; +import {Overlay, OverlayContainer, OverlayModule, FullscreenOverlayContainer} from './index'; + +describe('FullscreenOverlayContainer', () => { + let overlay: Overlay; + let overlayContainer: FullscreenOverlayContainer; + let fullscreenListeners: Set; + let fakeDocument: any; + + beforeEach(async(() => { + fullscreenListeners = new Set(); + + TestBed.configureTestingModule({ + imports: [OverlayTestModule], + providers: [{ + provide: DOCUMENT, + useFactory: () => { + // Provide a (very limited) stub for the document. This is the most practical solution for + // now since we only hit a handful of Document APIs. If we end up having to add more + // stubs here, we should reconsider whether to use a Proxy instead. Avoiding a proxy for + // now since it isn't supported on IE. See: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy + fakeDocument = { + body: document.body, + fullscreenElement: document.createElement('div'), + fullscreenEnabled: true, + addEventListener: function(eventName: string, listener: Function) { + if (eventName === 'fullscreenchange') { + fullscreenListeners.add(listener); + } else { + document.addEventListener.apply(document, arguments); + } + }, + removeEventListener: function(eventName: string, listener: Function) { + if (eventName === 'fullscreenchange') { + fullscreenListeners.delete(listener); + } else { + document.addEventListener.apply(document, arguments); + } + }, + querySelectorAll: function() { + return document.querySelectorAll.apply(document, arguments); + }, + createElement: function() { + return document.createElement.apply(document, arguments); + }, + }; + + return fakeDocument; + } + }] + }).compileComponents(); + })); + + beforeEach(inject([Overlay, OverlayContainer], (o: Overlay, oc: OverlayContainer) => { + overlay = o; + overlayContainer = oc as FullscreenOverlayContainer; + })); + + afterEach(() => { + overlayContainer.ngOnDestroy(); + fakeDocument = null; + }); + + it('should open an overlay inside a fullscreen element and move it to the body', () => { + const fixture = TestBed.createComponent(TestComponentWithTemplatePortals); + const overlayRef = overlay.create(); + const fullscreenElement = fakeDocument.fullscreenElement; + + overlayRef.attach(fixture.componentInstance.templatePortal); + fixture.detectChanges(); + + expect(fullscreenElement.contains(overlayRef.overlayElement)).toBe(true); + + fakeDocument.fullscreenElement = null; + fullscreenListeners.forEach(listener => listener()); + fixture.detectChanges(); + + expect(fullscreenElement.contains(overlayRef.overlayElement)).toBe(false); + expect(document.body.contains(overlayRef.overlayElement)).toBe(true); + }); + + it('should open an overlay inside the body and move it to a fullscreen element', () => { + const fullscreenElement = fakeDocument.fullscreenElement; + fakeDocument.fullscreenElement = null; + + const fixture = TestBed.createComponent(TestComponentWithTemplatePortals); + const overlayRef = overlay.create(); + + overlayRef.attach(fixture.componentInstance.templatePortal); + fixture.detectChanges(); + + expect(fullscreenElement.contains(overlayRef.overlayElement)).toBe(false); + expect(document.body.contains(overlayRef.overlayElement)).toBe(true); + + fakeDocument.fullscreenElement = fullscreenElement; + fullscreenListeners.forEach(listener => listener()); + fixture.detectChanges(); + + expect(fullscreenElement.contains(overlayRef.overlayElement)).toBe(true); + }); + +}); + +/** Test-bed component that contains a TempatePortal and an ElementRef. */ +@Component({ + template: `Cake`, + providers: [Overlay], +}) +class TestComponentWithTemplatePortals { + @ViewChild(CdkPortal) templatePortal: CdkPortal; + + constructor(public viewContainerRef: ViewContainerRef) { } +} + +@NgModule({ + imports: [OverlayModule, PortalModule], + declarations: [TestComponentWithTemplatePortals], + providers: [{ + provide: OverlayContainer, + useClass: FullscreenOverlayContainer + }] +}) +class OverlayTestModule { } diff --git a/src/e2e-app/e2e-app-module.ts b/src/e2e-app/e2e-app-module.ts index 8570f3eaf0b4..30bc6edbbd7f 100644 --- a/src/e2e-app/e2e-app-module.ts +++ b/src/e2e-app/e2e-app-module.ts @@ -1,7 +1,6 @@ import {DialogModule} from '@angular/cdk-experimental/dialog'; import {DragDropModule} from '@angular/cdk/drag-drop'; import {ScrollingModule as ExperimentalScrollingModule} from '@angular/cdk-experimental/scrolling'; -import {FullscreenOverlayContainer, OverlayContainer} from '@angular/cdk/overlay'; import {ScrollingModule} from '@angular/cdk/scrolling'; import {NgModule} from '@angular/core'; import {ReactiveFormsModule} from '@angular/forms'; @@ -35,7 +34,6 @@ import {SimpleCheckboxes} from './checkbox/checkbox-e2e'; import {DialogE2E, TestDialog} from './dialog/dialog-e2e'; import {E2EApp, Home} from './e2e-app/e2e-app'; import {E2E_APP_ROUTES} from './e2e-app/routes'; -import {FullscreenE2E, TestDialogFullScreen} from './fullscreen/fullscreen-e2e'; import {GridListE2E} from './grid-list/grid-list-e2e'; import {IconE2E} from './icon/icon-e2e'; import {InputE2E} from './input/input-e2e'; @@ -93,7 +91,6 @@ export class E2eMaterialModule {} ButtonE2E, DialogE2E, E2EApp, - FullscreenE2E, GridListE2E, Home, IconE2E, @@ -106,14 +103,10 @@ export class E2eMaterialModule {} SimpleRadioButtons, SlideToggleE2E, TestDialog, - TestDialogFullScreen, BlockScrollStrategyE2E, VirtualScrollE2E, ], bootstrap: [E2EApp], - providers: [ - {provide: OverlayContainer, useClass: FullscreenOverlayContainer} - ], - entryComponents: [TestDialog, TestDialogFullScreen] + entryComponents: [TestDialog] }) export class E2eAppModule { } diff --git a/src/e2e-app/e2e-app/e2e-app.html b/src/e2e-app/e2e-app/e2e-app.html index a28e711eaf86..75c422514f40 100644 --- a/src/e2e-app/e2e-app/e2e-app.html +++ b/src/e2e-app/e2e-app/e2e-app.html @@ -7,7 +7,6 @@ Checkbox Dialog Expansion - Fullscreen Grid list Icon Input diff --git a/src/e2e-app/e2e-app/routes.ts b/src/e2e-app/e2e-app/routes.ts index 58a2e48e7b7b..12c2d0c5833e 100644 --- a/src/e2e-app/e2e-app/routes.ts +++ b/src/e2e-app/e2e-app/routes.ts @@ -12,7 +12,6 @@ import {GridListE2E} from '../grid-list/grid-list-e2e'; import {ProgressBarE2E} from '../progress-bar/progress-bar-e2e'; 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 {SidenavE2E} from '../sidenav/sidenav-e2e'; import {BlockScrollStrategyE2E} from '../block-scroll-strategy/block-scroll-strategy-e2e'; @@ -33,7 +32,6 @@ export const E2E_APP_ROUTES: Routes = [ {path: 'checkbox', component: SimpleCheckboxes}, {path: 'dialog', component: DialogE2E}, {path: 'expansion', component: ExpansionOverviewExample}, - {path: 'fullscreen', component: FullscreenE2E}, {path: 'grid-list', component: GridListE2E}, {path: 'icon', component: IconE2E}, {path: 'input', component: InputE2E}, diff --git a/src/e2e-app/fullscreen/fullscreen-e2e.html b/src/e2e-app/fullscreen/fullscreen-e2e.html deleted file mode 100644 index 834885caefb1..000000000000 --- a/src/e2e-app/fullscreen/fullscreen-e2e.html +++ /dev/null @@ -1,6 +0,0 @@ - - -
- - -
diff --git a/src/e2e-app/fullscreen/fullscreen-e2e.ts b/src/e2e-app/fullscreen/fullscreen-e2e.ts deleted file mode 100644 index 3eea5a9baf25..000000000000 --- a/src/e2e-app/fullscreen/fullscreen-e2e.ts +++ /dev/null @@ -1,62 +0,0 @@ -import {Component, ElementRef, Output, EventEmitter} from '@angular/core'; -import {MatDialog, MatDialogRef} from '@angular/material'; - -@Component({ - moduleId: module.id, - selector: 'fullscreen-e2e', - templateUrl: 'fullscreen-e2e.html' -}) -export class FullscreenE2E { - - dialogRef: MatDialogRef | null; - - constructor (private _element: ElementRef, private _dialog: MatDialog) { } - - openDialog() { - this.dialogRef = this._dialog.open(TestDialogFullScreen); - - this.dialogRef.componentInstance.openFullscreen.subscribe(() => this.openFullscreen()); - this.dialogRef.componentInstance.exitFullscreen.subscribe(() => this.exitFullscreen()); - this.dialogRef.afterClosed().subscribe(() => this.dialogRef = null); - } - - openFullscreen() { - let element = this._element.nativeElement.querySelector('#fullscreen-pane') as any; - - if (element.requestFullscreen) { - element.requestFullscreen(); - } else if (element.webkitRequestFullScreen) { - element.webkitRequestFullScreen(); - } else if (element.mozRequestFullScreen) { - element.mozRequestFullScreen(); - } else if (element.msRequestFullScreen) { - element.msRequestFullScreen(); - } - } - - exitFullscreen() { - if (document.exitFullscreen) { - document.exitFullscreen(); - } else if ((document as any).webkitExitFullscreen) { - (document as any).webkitExitFullscreen(); - } else if ((document as any).mozExitFullScreen) { - (document as any).mozExitFullScreen(); - } else if ((document as any).msExitFullScreen) { - (document as any).msExitFullScreen(); - } - } -} - -@Component({ - template: ` - - - - ` -}) -export class TestDialogFullScreen { - @Output() openFullscreen = new EventEmitter(); - @Output() exitFullscreen = new EventEmitter(); - - constructor(public dialogRef: MatDialogRef) {} -}