Skip to content

Commit

Permalink
feat(overlay): add fullscreen-enabled overlay class (#1949)
Browse files Browse the repository at this point in the history
* feat(overlay): add fullscreen overlay class

* fix lint error

* move fs container to a new file and rename it

* add e2e tests

* fix tests

* rebased and fix comments

* fix typings

* fix e2e tests

* address comments

* fix tests
  • Loading branch information
quanterion authored and tinayuangao committed Jan 11, 2017
1 parent f9dd34f commit 0640302
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 10 deletions.
38 changes: 38 additions & 0 deletions e2e/components/fullscreen/fullscreen.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {browser, by, element, Key, ProtractorBy} from 'protractor';

describe('fullscreen', () => {
beforeEach(() => browser.get('/fullscreen'));

let overlayInBody = () =>
browser.isElementPresent(by.css('body > .cdk-overlay-container') as ProtractorBy);
let overlayInFullscreen = () =>
browser.isElementPresent(by.css('#fullscreenpane > .cdk-overlay-container') as ProtractorBy);

it('should open a dialog inside a fullscreen element and move it to the document body', () => {
element(by.id('fullscreen')).click();
element(by.id('dialog')).click();

overlayInFullscreen().then((isPresent: boolean) => {
expect(isPresent).toBe(true);
element(by.id('exitfullscreenindialog')).click();
overlayInBody().then((isPresent: boolean) => {
expect(isPresent).toBe(true);
});
});
});

it('should open a dialog inside the document body and move it to a fullscreen element', () => {
element(by.id('dialog')).click();
overlayInBody().then((isPresent: boolean) => {
expect(isPresent).toBe(true);
element(by.id('fullscreenindialog')).click();
overlayInFullscreen().then((isPresent: boolean) => {
expect(isPresent).toBe(true);
element(by.id('exitfullscreenindialog')).click();
overlayInBody().then((isPresent: boolean) => {
expect(isPresent).toBe(true);
});
});
});
});
});
6 changes: 5 additions & 1 deletion src/demo-app/demo-app-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {HttpModule} from '@angular/http';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import {DemoApp, Home} from './demo-app/demo-app';
import {RouterModule} from '@angular/router';
import {MaterialModule} from '@angular/material';
import {MaterialModule, OverlayContainer,
FullscreenOverlayContainer} from '@angular/material';
import {DEMO_APP_ROUTES} from './demo-app/routes';
import {ProgressBarDemo} from './progress-bar/progress-bar-demo';
import {JazzDialog, ContentElementDialog, DialogDemo} from './dialog/dialog-demo';
Expand Down Expand Up @@ -94,6 +95,9 @@ import {InputContainerDemo} from './input/input-container-demo';
FoggyTabContent,
PlatformDemo
],
providers: [
{provide: OverlayContainer, useClass: FullscreenOverlayContainer}
],
entryComponents: [
DemoApp,
JazzDialog,
Expand Down
3 changes: 3 additions & 0 deletions src/demo-app/demo-app/demo-app.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
</button>
<div class="demo-toolbar">
<h1>Angular Material 2 Demos</h1>
<button md-button (click)="toggleFullscreen()" title="Toggle fullscreen">
Fullscreen
</button>
<button md-button (click)="root.dir = (root.dir == 'rtl' ? 'ltr' : 'rtl')" title="Toggle between RTL and LTR">
{{root.dir.toUpperCase()}}
</button>
Expand Down
6 changes: 6 additions & 0 deletions src/demo-app/demo-app/demo-app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@ body {
font-size: 20px;
}
}

// stretch to screen size in fullscreen mode
.demo-content {
width: 100%;
height: 100%;
}
19 changes: 18 additions & 1 deletion src/demo-app/demo-app/demo-app.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Component, ViewEncapsulation} from '@angular/core';
import {Component, ViewEncapsulation, ElementRef} from '@angular/core';


@Component({
Expand Down Expand Up @@ -52,4 +52,21 @@ export class DemoApp {
{name: 'Tooltip', route: 'tooltip'},
{name: 'Platform', route: 'platform'}
];

constructor(private _element: ElementRef) {

}

toggleFullscreen() {
let elem = this._element.nativeElement.querySelector('.demo-content');
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.webkitRequestFullScreen) {
elem.webkitRequestFullScreen();
} else if (elem.mozRequestFullScreen) {
elem.mozRequestFullScreen();
} else if (elem.msRequestFullScreen) {
elem.msRequestFullScreen();
}
}
}
13 changes: 8 additions & 5 deletions src/e2e-app/e2e-app-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import {GridListE2E} from './grid-list/grid-list-e2e';
import {ListE2E} from './list/list-e2e';
import {ProgressBarE2E} from './progress-bar/progress-bar-e2e';
import {ProgressSpinnerE2E} from './progress-spinner/progress-spinner-e2e';
import {MaterialModule} from '@angular/material';
import {FullscreenE2E, TestDialog as TestDialogFullScreen} from './fullscreen/fullscreen-e2e';
import {MaterialModule, OverlayContainer, FullscreenOverlayContainer} from '@angular/material';
import {E2E_APP_ROUTES} from './e2e-app/routes';
import {SlideToggleE2E} from './slide-toggle/slide-toggle-e2e';


@NgModule({
imports: [
BrowserModule,
Expand All @@ -39,12 +39,15 @@ import {SlideToggleE2E} from './slide-toggle/slide-toggle-e2e';
ListE2E,
ProgressBarE2E,
ProgressSpinnerE2E,
SlideToggleE2E
SlideToggleE2E,
FullscreenE2E,
TestDialogFullScreen
],
bootstrap: [E2EApp],
providers: [
{provide: AnimationDriver, useValue: AnimationDriver.NOOP}
{provide: AnimationDriver, useValue: AnimationDriver.NOOP},
{provide: OverlayContainer, useClass: FullscreenOverlayContainer}
],
entryComponents: [TestDialog]
entryComponents: [TestDialog, TestDialogFullScreen]
})
export class E2eAppModule { }
1 change: 1 addition & 0 deletions src/e2e-app/e2e-app/e2e-app.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<a md-list-item [routerLink]="['radio']">Radios</a>
<a md-list-item [routerLink]="['slide-toggle']">Slide Toggle</a>
<a md-list-item [routerLink]="['tabs']">Tabs</a>
<a md-list-item [routerLink]="['fullscreen']">Fullscreen</a>
</md-nav-list>

<main>
Expand Down
4 changes: 3 additions & 1 deletion src/e2e-app/e2e-app/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {ListE2E} from '../list/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';

export const E2E_APP_ROUTES: Routes = [
{path: '', component: Home},
Expand All @@ -26,5 +27,6 @@ export const E2E_APP_ROUTES: Routes = [
{path: 'list', component: ListE2E},
{path: 'progress-bar', component: ProgressBarE2E},
{path: 'progress-spinner', component: ProgressSpinnerE2E},
{path: 'slide-toggle', component: SlideToggleE2E}
{path: 'slide-toggle', component: SlideToggleE2E},
{path: 'fullscreen', component: FullscreenE2E}
];
5 changes: 5 additions & 0 deletions src/e2e-app/fullscreen/fullscreen-e2e.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<button id="fullscreen" (click)="toggleFullScreen()">FULLSCREEN</button>
<div id="fullscreenpane" style="width: 100%; height: 100%">
<button id="dialog" (click)="openDialog()">DIALOG</button>
<button id="exitfullscreen" (click)="exitFullscreen()">EXIT FULLSCREEN</button>
</div>
61 changes: 61 additions & 0 deletions src/e2e-app/fullscreen/fullscreen-e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {Component, ElementRef, Output, EventEmitter} from '@angular/core';
import {MdDialog, MdDialogRef} from '@angular/material';

@Component({
selector: 'fullscreen-e2e',
moduleId: module.id,
templateUrl: 'fullscreen-e2e.html'
})
export class FullscreenE2E {
dialogRef: MdDialogRef<TestDialog>;

constructor (private _element: ElementRef, private _dialog: MdDialog) { }

openDialog() {
this.dialogRef = this._dialog.open(TestDialog);
this.dialogRef.componentInstance.fullscreen.subscribe(() => this.toggleFullScreen());
this.dialogRef.componentInstance.exitfullscreen.subscribe(() => this.exitFullscreen());
this.dialogRef.afterClosed().subscribe(() => {
this.dialogRef = null;
});
}

toggleFullScreen() {
let element = this._element.nativeElement.querySelector('#fullscreenpane');
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
} else if ((element as any).mozRequestFullScreen) {
(element as any).mozRequestFullScreen();
} else if ((element as any).msRequestFullScreen) {
(element as any).msRequestFullScreen();
}
}

exitFullscreen() {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if ((document as any).mozExitFullScreen) {
(document as any).mozExitFullScreen();
} else if ((document as any).msExitFullScreen) {
(document as any).msExitFullScreen();
}
}
}

@Component({
selector: 'fullscreen-dialog-e2e-test',
template: `
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
<button id="fullscreenindialog" (click)="fullscreen.emit()">FULLSCREEN</button>
<button id="exitfullscreenindialog" (click)="exitfullscreen.emit()">EXIT FULLSCREEN</button>
<button type="button" (click)="dialogRef.close()" id="close">CLOSE</button>`
})
export class TestDialog {
constructor(public dialogRef: MdDialogRef<TestDialog>) { }
@Output() fullscreen = new EventEmitter<void>();
@Output() exitfullscreen = new EventEmitter<void>();
}
1 change: 1 addition & 0 deletions src/lib/core/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export {Platform as MdPlatform} from './platform/platform';
// Overlay
export {Overlay, OVERLAY_PROVIDERS} from './overlay/overlay';
export {OverlayContainer} from './overlay/overlay-container';
export {FullscreenOverlayContainer} from './overlay/fullscreen-overlay-container';
export {OverlayRef} from './overlay/overlay-ref';
export {OverlayState} from './overlay/overlay-state';
export {
Expand Down
53 changes: 53 additions & 0 deletions src/lib/core/overlay/fullscreen-overlay-container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {Injectable} from '@angular/core';
import {OverlayContainer} from './overlay-container';

/**
* The FullscreenOverlayContainer is the alternative to OverlayContainer
* that supports correct displaying of overlay elements in Fullscreen mode
* https://developer.mozilla.org/en-US/docs/Web/API/Element/requestFullScreen
* It should be provided in the root component that way:
* providers: [
* {provide: OverlayContainer, useClass: FullscreenOverlayContainer}
* ],
*/
@Injectable()
export class FullscreenOverlayContainer extends OverlayContainer {
protected _createContainer(): void {
super._createContainer();
this._adjustParentForFullscreenChange();
this._addFullscreenChangeListener(() => this._adjustParentForFullscreenChange());
}

private _adjustParentForFullscreenChange(): void {
if (!this._containerElement) {
return;
}
let fullscreenElement = this.getFullscreenElement();
let parent = fullscreenElement || document.body;
parent.appendChild(this._containerElement);
}

private _addFullscreenChangeListener(fn: () => void) {
if (document.fullscreenEnabled) {
document.addEventListener('fullscreenchange', fn);
} else if (document.webkitFullscreenEnabled) {
document.addEventListener('webkitfullscreenchange', fn);
} else if ((document as any).mozFullScreenEnabled) {
document.addEventListener('mozfullscreenchange', fn);
} else if ((document as any).msFullscreenEnabled) {
document.addEventListener('MSFullscreenChange', fn);
}
}

/**
* When the page is put into fullscreen mode, a specific element is specified.
* Only that element and its children are visible when in fullscreen mode.
*/
getFullscreenElement(): Element {
return document.fullscreenElement ||
document.webkitFullscreenElement ||
(document as any).mozFullScreenElement ||
(document as any).msFullscreenElement ||
null;
}
}
7 changes: 5 additions & 2 deletions src/lib/core/overlay/overlay-container.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import {Injectable} from '@angular/core';

/**
* The OverlayContainer is the container in which all overlays will load.
* It should be provided in the root component to ensure it is properly shared.
*/
@Injectable()
export class OverlayContainer {
private _containerElement: HTMLElement;
protected _containerElement: HTMLElement;

/**
* This method returns the overlay container element. It will lazily
Expand All @@ -20,7 +23,7 @@ export class OverlayContainer {
* Create the overlay container element, which is simply a div
* with the 'cdk-overlay-container' class on the document body.
*/
private _createContainer(): void {
protected _createContainer(): void {
let container = document.createElement('div');
container.classList.add('cdk-overlay-container');
document.body.appendChild(container);
Expand Down

0 comments on commit 0640302

Please sign in to comment.