Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(overlay): add fullscreen-enabled overlay class #1949

Merged
merged 10 commits into from
Jan 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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