-
Notifications
You must be signed in to change notification settings - Fork 6.7k
/
dialog-container.ts
98 lines (84 loc) · 3.11 KB
/
dialog-container.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import {
Component,
ComponentRef,
ViewChild,
ViewEncapsulation,
NgZone,
OnDestroy,
} from '@angular/core';
import {BasePortalHost, ComponentPortal, PortalHostDirective, TemplatePortal} from '../core';
import {MdDialogConfig} from './dialog-config';
import {MdDialogRef} from './dialog-ref';
import {MdDialogContentAlreadyAttachedError} from './dialog-errors';
import {FocusTrap} from '../core/a11y/focus-trap';
import 'rxjs/add/operator/first';
/**
* Internal component that wraps user-provided dialog content.
* @docs-private
*/
@Component({
moduleId: module.id,
selector: 'md-dialog-container, mat-dialog-container',
templateUrl: 'dialog-container.html',
styleUrls: ['dialog.css'],
host: {
'class': 'md-dialog-container',
'[attr.role]': 'dialogConfig?.role',
'(keydown.escape)': 'handleEscapeKey()',
},
encapsulation: ViewEncapsulation.None,
})
export class MdDialogContainer extends BasePortalHost implements OnDestroy {
/** The portal host inside of this container into which the dialog content will be loaded. */
@ViewChild(PortalHostDirective) _portalHost: PortalHostDirective;
/** The directive that traps and manages focus within the dialog. */
@ViewChild(FocusTrap) _focusTrap: FocusTrap;
/** Element that was focused before the dialog was opened. Save this to restore upon close. */
private _elementFocusedBeforeDialogWasOpened: Element = null;
/** The dialog configuration. */
dialogConfig: MdDialogConfig;
/** Reference to the open dialog. */
dialogRef: MdDialogRef<any>;
constructor(private _ngZone: NgZone) {
super();
}
/**
* Attach a portal as content to this dialog container.
* @param portal Portal to be attached as the dialog content.
*/
attachComponentPortal<T>(portal: ComponentPortal<T>): ComponentRef<T> {
if (this._portalHost.hasAttached()) {
throw new MdDialogContentAlreadyAttachedError();
}
let attachResult = this._portalHost.attachComponentPortal(portal);
// If were to attempt to focus immediately, then the content of the dialog would not yet be
// ready in instances where change detection has to run first. To deal with this, we simply
// wait for the microtask queue to be empty.
this._ngZone.onMicrotaskEmpty.first().subscribe(() => {
this._elementFocusedBeforeDialogWasOpened = document.activeElement;
this._focusTrap.focusFirstTabbableElement();
});
return attachResult;
}
/** @docs-private */
attachTemplatePortal(portal: TemplatePortal): Map<string, any> {
throw Error('Not yet implemented');
}
/**
* Handles the user pressing the Escape key.
* @docs-private
*/
handleEscapeKey() {
if (!this.dialogConfig.disableClose) {
this.dialogRef.close();
}
}
ngOnDestroy() {
// When the dialog is destroyed, return focus to the element that originally had it before
// the dialog was opened. Wait for the DOM to finish settling before changing the focus so
// that it doesn't end up back on the <body>.
this._ngZone.onMicrotaskEmpty.first().subscribe(() => {
(this._elementFocusedBeforeDialogWasOpened as HTMLElement).focus();
});
}
}