@angular-mdc/web
Version:
1,349 lines (1,341 loc) • 50.6 kB
JavaScript
/**
* @license
* Copyright (c) Dominic Carretto
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://github.com/trimox/angular-mdc-web/blob/master/LICENSE
*/
import { Directive, ElementRef, Input, Component, ViewEncapsulation, ChangeDetectionStrategy, NgZone, ContentChild, ContentChildren, Optional, Inject, ViewChild, InjectionToken, TemplateRef, Injectable, Injector, SkipSelf, NgModule } from '@angular/core';
import { Overlay, OverlayModule } from '@angular/cdk/overlay';
import { CdkPortalOutlet, BasePortalOutlet, PortalInjector, ComponentPortal, TemplatePortal, PortalModule } from '@angular/cdk/portal';
import { __extends, __assign } from 'tslib';
import { Platform } from '@angular/cdk/platform';
import { Subject, merge, fromEvent, defer } from 'rxjs';
import { takeUntil, startWith } from 'rxjs/operators';
import { MDCComponent } from '@angular-mdc/web/base';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { MdcButton } from '@angular-mdc/web/button';
import { MdcRipple } from '@angular-mdc/web/ripple';
import { matches, closest } from '@angular-mdc/web/dom';
import { MDCDialogFoundation, util, strings } from '@material/dialog';
import { DOCUMENT } from '@angular/common';
import { FocusTrapFactory } from '@angular/cdk/a11y';
/**
* @fileoverview added by tsickle
* Generated from: dialog/dialog-directives.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
var MdcDialogAction = /** @class */ (function () {
function MdcDialogAction(elementRef) {
this.elementRef = elementRef;
this._action = '';
}
Object.defineProperty(MdcDialogAction.prototype, "action", {
get: /**
* @return {?}
*/
function () { return this._action; },
set: /**
* @param {?} action
* @return {?}
*/
function (action) {
// If the directive is set without a name (updated programatically), then this setter will
// trigger with an empty string and should not overwrite the programatically set value.
if (!action) {
return;
}
this._action = action;
this.elementRef.nativeElement.setAttribute('data-mdc-dialog-action', this._action);
},
enumerable: true,
configurable: true
});
MdcDialogAction.decorators = [
{ type: Directive, args: [{ selector: '[mdcDialogAction]' },] },
];
/** @nocollapse */
MdcDialogAction.ctorParameters = function () { return [
{ type: ElementRef }
]; };
MdcDialogAction.propDecorators = {
action: [{ type: Input, args: ['mdcDialogAction',] }]
};
return MdcDialogAction;
}());
var MdcDialogScrim = /** @class */ (function () {
function MdcDialogScrim(elementRef) {
this.elementRef = elementRef;
}
MdcDialogScrim.decorators = [
{ type: Directive, args: [{
selector: 'mdc-dialog-scrim',
host: { 'class': 'mdc-dialog__scrim' }
},] },
];
/** @nocollapse */
MdcDialogScrim.ctorParameters = function () { return [
{ type: ElementRef }
]; };
return MdcDialogScrim;
}());
var MdcDialogContainer = /** @class */ (function () {
function MdcDialogContainer(elementRef) {
this.elementRef = elementRef;
}
MdcDialogContainer.decorators = [
{ type: Directive, args: [{
selector: '[mdcDialogContainer], mdc-dialog-container',
host: { 'class': 'mdc-dialog__container' }
},] },
];
/** @nocollapse */
MdcDialogContainer.ctorParameters = function () { return [
{ type: ElementRef }
]; };
return MdcDialogContainer;
}());
var MdcDialogSurface = /** @class */ (function () {
function MdcDialogSurface(elementRef) {
this.elementRef = elementRef;
}
MdcDialogSurface.decorators = [
{ type: Directive, args: [{
selector: '[mdcDialogSurface], mdc-dialog-surface',
host: { 'class': 'mdc-dialog__surface' }
},] },
];
/** @nocollapse */
MdcDialogSurface.ctorParameters = function () { return [
{ type: ElementRef }
]; };
return MdcDialogSurface;
}());
var MdcDialogTitle = /** @class */ (function () {
function MdcDialogTitle(elementRef) {
this.elementRef = elementRef;
}
MdcDialogTitle.decorators = [
{ type: Directive, args: [{
selector: '[mdcDialogTitle], mdc-dialog-title',
host: { 'class': 'mdc-dialog__title' }
},] },
];
/** @nocollapse */
MdcDialogTitle.ctorParameters = function () { return [
{ type: ElementRef }
]; };
return MdcDialogTitle;
}());
var MdcDialogContent = /** @class */ (function () {
function MdcDialogContent(elementRef) {
this.elementRef = elementRef;
}
MdcDialogContent.decorators = [
{ type: Directive, args: [{
selector: '[mdcDialogContent], mdc-dialog-content',
host: { 'class': 'mdc-dialog__content' }
},] },
];
/** @nocollapse */
MdcDialogContent.ctorParameters = function () { return [
{ type: ElementRef }
]; };
return MdcDialogContent;
}());
var MdcDialogActions = /** @class */ (function () {
function MdcDialogActions(elementRef) {
this.elementRef = elementRef;
this._stacked = false;
}
Object.defineProperty(MdcDialogActions.prototype, "stacked", {
get: /**
* @return {?}
*/
function () { return this._stacked; },
set: /**
* @param {?} value
* @return {?}
*/
function (value) {
this._stacked = coerceBooleanProperty(value);
},
enumerable: true,
configurable: true
});
MdcDialogActions.decorators = [
{ type: Component, args: [{selector: 'mdc-dialog-actions, [mdcDialogActions]',
template: '<ng-content></ng-content>',
exportAs: 'mdcDialogActions',
host: {
'class': 'mdc-dialog__actions',
'[class.mdc-dialog--stacked]': 'stacked'
},
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
},] },
];
/** @nocollapse */
MdcDialogActions.ctorParameters = function () { return [
{ type: ElementRef }
]; };
MdcDialogActions.propDecorators = {
stacked: [{ type: Input }]
};
return MdcDialogActions;
}());
var MdcDialogButton = /** @class */ (function (_super) {
__extends(MdcDialogButton, _super);
function MdcDialogButton() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this._default = false;
return _this;
}
Object.defineProperty(MdcDialogButton.prototype, "default", {
get: /**
* @return {?}
*/
function () { return this._default; },
set: /**
* @param {?} value
* @return {?}
*/
function (value) {
this._default = coerceBooleanProperty(value);
},
enumerable: true,
configurable: true
});
MdcDialogButton.decorators = [
{ type: Component, args: [{selector: '[mdcDialogButton]',
exportAs: 'mdcDialogButton',
host: {
'class': 'mdc-dialog__button',
'[class.mdc-button]': 'true',
'[class.mdc-dialog__button--default]': 'default'
},
template: "\n <div class=\"mdc-button__ripple\"></div>\n <ng-content></ng-content>",
providers: [MdcRipple],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
},] },
];
MdcDialogButton.propDecorators = {
default: [{ type: Input }]
};
return MdcDialogButton;
}(MdcButton));
/**
* @fileoverview added by tsickle
* Generated from: dialog/dialog-ref.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Unique id for the created dialog.
* @type {?}
*/
var uniqueId = 0;
/**
* Reference to a dialog dispatched from the MdcDialog service.
* @template T, R
*/
var /**
* Reference to a dialog dispatched from the MdcDialog service.
* @template T, R
*/
MdcDialogRef = /** @class */ (function () {
function MdcDialogRef(_overlayRef, _portalInstance, id) {
var _this = this;
if (id === void 0) { id = "mdc-dialog-" + uniqueId++; }
this._overlayRef = _overlayRef;
this._portalInstance = _portalInstance;
this.id = id;
/**
* Subject for notifying the user that the dialog has finished opening.
*/
this._afterOpened = new Subject();
/**
* Subject for notifying the user that the dialog has started closing.
*/
this._beforeClosed = new Subject();
/**
* Subject for notifying the user that the dialog has finished closing.
*/
this._afterClosed = new Subject();
// Pass the id along to the portal.
_portalInstance._id = id;
_overlayRef.detachments().subscribe((/**
* @return {?}
*/
function () {
_this._beforeClosed.next(_this._result);
_this._beforeClosed.complete();
_this._afterClosed.next(_this._result);
_this._afterClosed.complete();
_this.componentInstance = (/** @type {?} */ (null));
_this._overlayRef.dispose();
}));
}
/**
* Close the dialog.
* @param dialogResult Optional result to return to the dialog opener.
*/
/**
* Close the dialog.
* @param {?=} dialogResult Optional result to return to the dialog opener.
* @return {?}
*/
MdcDialogRef.prototype.close = /**
* Close the dialog.
* @param {?=} dialogResult Optional result to return to the dialog opener.
* @return {?}
*/
function (dialogResult) {
this._result = dialogResult;
this._overlayRef.dispose();
};
/** Marks the dialog as opened. */
/**
* Marks the dialog as opened.
* @return {?}
*/
MdcDialogRef.prototype.opened = /**
* Marks the dialog as opened.
* @return {?}
*/
function () {
if (!this._afterOpened.closed) {
this._afterOpened.next();
this._afterOpened.complete();
}
};
/** Gets an observable that is notified when the dialog is finished opening. */
/**
* Gets an observable that is notified when the dialog is finished opening.
* @return {?}
*/
MdcDialogRef.prototype.afterOpened = /**
* Gets an observable that is notified when the dialog is finished opening.
* @return {?}
*/
function () {
return this._afterOpened.asObservable();
};
/** Gets an observable that is notified when the dialog has started closing. */
/**
* Gets an observable that is notified when the dialog has started closing.
* @return {?}
*/
MdcDialogRef.prototype.beforeClosed = /**
* Gets an observable that is notified when the dialog has started closing.
* @return {?}
*/
function () {
return this._beforeClosed.asObservable();
};
/** Gets an observable that is notified when the dialog is finished closing. */
/**
* Gets an observable that is notified when the dialog is finished closing.
* @return {?}
*/
MdcDialogRef.prototype.afterClosed = /**
* Gets an observable that is notified when the dialog is finished closing.
* @return {?}
*/
function () {
return this._afterClosed.asObservable();
};
return MdcDialogRef;
}());
/**
* @fileoverview added by tsickle
* Generated from: dialog/dialog.component.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
var LAYOUT_EVENTS = ['resize', 'orientationchange'];
var MdcDialogComponent = /** @class */ (function (_super) {
__extends(MdcDialogComponent, _super);
function MdcDialogComponent(_ngZone, _platform, elementRef, dialogRef) {
var _this = _super.call(this, elementRef) || this;
_this._ngZone = _ngZone;
_this._platform = _platform;
_this.elementRef = elementRef;
_this.dialogRef = dialogRef;
/**
* Emits whenever the component is destroyed.
*/
_this._destroy = new Subject();
_this._scrollable = true;
_this._layoutEventSubscription = null;
_this.config = dialogRef._portalInstance._config;
return _this;
}
Object.defineProperty(MdcDialogComponent.prototype, "layoutEvents", {
/** Combined stream of all of the dialog layout events. */
get: /**
* Combined stream of all of the dialog layout events.
* @return {?}
*/
function () {
return merge.apply(void 0, LAYOUT_EVENTS.map((/**
* @param {?} evt
* @return {?}
*/
function (evt) { return fromEvent(window, evt); })));
},
enumerable: true,
configurable: true
});
/**
* @return {?}
*/
MdcDialogComponent.prototype.getDefaultFoundation = /**
* @return {?}
*/
function () {
var _this = this;
/** @type {?} */
var adapter = {
addClass: (/**
* @param {?} className
* @return {?}
*/
function (className) { return _this._getDialog().classList.add(className); }),
removeClass: (/**
* @param {?} className
* @return {?}
*/
function (className) { return _this._getDialog().classList.remove(className); }),
getInitialFocusEl: (/**
* @return {?}
*/
function () { return _this._platform.isBrowser
? (/** @type {?} */ (document.querySelector("[cdkFocusInitial]"))) : null; }),
hasClass: (/**
* @param {?} className
* @return {?}
*/
function (className) { return _this._getDialog().classList.contains(className); }),
addBodyClass: (/**
* @param {?} className
* @return {?}
*/
function (className) {
if (_this._platform.isBrowser) {
(/** @type {?} */ (document.body)).classList.add(className);
}
}),
removeBodyClass: (/**
* @param {?} className
* @return {?}
*/
function (className) {
if (_this._platform.isBrowser) {
(/** @type {?} */ (document.body)).classList.remove(className);
}
}),
eventTargetMatches: (/**
* @param {?} target
* @param {?} selector
* @return {?}
*/
function (target, selector) { return matches((/** @type {?} */ (target)), selector); }),
trapFocus: (/**
* @return {?}
*/
function () { }),
releaseFocus: (/**
* @return {?}
*/
function () { }),
isContentScrollable: (/**
* @return {?}
*/
function () {
return !!_this._content && _this._scrollable && util.isScrollable(_this._content.elementRef.nativeElement);
}),
areButtonsStacked: (/**
* @return {?}
*/
function () { return util.areTopsMisaligned((/** @type {?} */ (_this._buttons))); }),
getActionFromEvent: (/**
* @param {?} event
* @return {?}
*/
function (event) {
/** @type {?} */
var element = closest((/** @type {?} */ (event.target)), "[" + strings.ACTION_ATTRIBUTE + "]");
return element && element.getAttribute(strings.ACTION_ATTRIBUTE);
}),
clickDefaultButton: (/**
* @return {?}
*/
function () {
var _a, _b, _c;
/** @type {?} */
var defaultBtn = _this._buttons.find((/**
* @param {?} _
* @return {?}
*/
function (_) { return _.default; }));
(_c = (_b = (_a = defaultBtn) === null || _a === void 0 ? void 0 : _a.elementRef) === null || _b === void 0 ? void 0 : _b.nativeElement) === null || _c === void 0 ? void 0 : _c.click();
}),
reverseButtons: (/**
* @return {?}
*/
function () {
_this._buttons.toArray().reverse();
_this._buttons.forEach((/**
* @param {?} button
* @return {?}
*/
function (button) { return (/** @type {?} */ (button.getHostElement().parentElement)).appendChild(button.getHostElement()); }));
}),
notifyOpened: (/**
* @return {?}
*/
function () { return _this.dialogRef.opened(); }),
notifyOpening: (/**
* @return {?}
*/
function () { }),
notifyClosed: (/**
* @param {?} action
* @return {?}
*/
function (action) { return _this._closeDialogByRef(action); }),
notifyClosing: (/**
* @return {?}
*/
function () { })
};
return new MDCDialogFoundation(adapter);
};
/**
* @return {?}
*/
MdcDialogComponent.prototype.ngAfterViewInit = /**
* @return {?}
*/
function () {
this._foundation = this.getDefaultFoundation();
this._initialize();
this._loadListeners();
this._foundation.open();
};
/**
* @private
* @return {?}
*/
MdcDialogComponent.prototype._initialize = /**
* @private
* @return {?}
*/
function () {
this._scrollable = !!this.config.scrollable;
if (!this.config.clickOutsideToClose) {
this._foundation.setScrimClickAction('');
}
if (!this.config.escapeToClose) {
this._foundation.setEscapeKeyAction('');
}
if (!this.config.buttonsStacked) {
this._foundation.setAutoStackButtons(false);
}
};
/**
* @return {?}
*/
MdcDialogComponent.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
var _a, _b;
this._destroy.next();
this._destroy.complete();
(_a = this._layoutEventSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
(_b = this._foundation) === null || _b === void 0 ? void 0 : _b.destroy();
};
/** Recalculates layout and automatically adds/removes modifier classes like --scrollable. */
/**
* Recalculates layout and automatically adds/removes modifier classes like --scrollable.
* @return {?}
*/
MdcDialogComponent.prototype.layout = /**
* Recalculates layout and automatically adds/removes modifier classes like --scrollable.
* @return {?}
*/
function () {
this._foundation.layout();
};
/**
* @param {?} evt
* @return {?}
*/
MdcDialogComponent.prototype._onKeydown = /**
* @param {?} evt
* @return {?}
*/
function (evt) {
this._foundation.handleKeydown(evt);
};
/**
* @param {?} evt
* @return {?}
*/
MdcDialogComponent.prototype._onClick = /**
* @param {?} evt
* @return {?}
*/
function (evt) {
this._foundation.handleClick(evt);
};
/**
* @private
* @param {?=} action
* @return {?}
*/
MdcDialogComponent.prototype._closeDialogByRef = /**
* @private
* @param {?=} action
* @return {?}
*/
function (action) {
this.dialogRef.close(action);
};
/**
* @private
* @return {?}
*/
MdcDialogComponent.prototype._loadListeners = /**
* @private
* @return {?}
*/
function () {
var _this = this;
this._layoutEventSubscription = this.layoutEvents.pipe()
.subscribe((/**
* @return {?}
*/
function () { return _this.layout(); }));
if (this._platform.isBrowser) {
this._ngZone.runOutsideAngular((/**
* @return {?}
*/
function () {
return fromEvent(document, 'keydown').pipe(takeUntil(_this._destroy))
.subscribe((/**
* @param {?} evt
* @return {?}
*/
function (evt) { return _this._ngZone.run((/**
* @return {?}
*/
function () { return _this._foundation.handleDocumentKeydown(evt); })); }));
}));
}
};
/** Retrieves the DOM element of the component host. */
/**
* Retrieves the DOM element of the component host.
* @private
* @return {?}
*/
MdcDialogComponent.prototype._getDialog = /**
* Retrieves the DOM element of the component host.
* @private
* @return {?}
*/
function () {
return this._elementRef.nativeElement;
};
MdcDialogComponent.decorators = [
{ type: Component, args: [{selector: 'mdc-dialog',
exportAs: 'mdc-dialog',
host: {
'[attr.id]': 'config?.id',
'role': 'alertdialog',
'class': 'mdc-dialog',
'[attr.aria-modal]': 'true',
'[attr.aria-labelledby]': 'config?.ariaLabel',
'[attr.aria-label]': 'config?.ariaLabel',
'[attr.aria-describedby]': 'config?.ariaDescribedBy || null',
'(click)': '_onClick($event)',
'(keydown)': '_onKeydown($event)'
},
template: "\n <mdc-dialog-scrim></mdc-dialog-scrim>\n <ng-content></ng-content>",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
},] },
];
/** @nocollapse */
MdcDialogComponent.ctorParameters = function () { return [
{ type: NgZone },
{ type: Platform },
{ type: ElementRef },
{ type: MdcDialogRef }
]; };
MdcDialogComponent.propDecorators = {
_surface: [{ type: ContentChild, args: [MdcDialogSurface, { static: false },] }],
_content: [{ type: ContentChild, args: [MdcDialogContent, { static: false },] }],
_buttons: [{ type: ContentChildren, args: [MdcDialogButton, { descendants: true },] }]
};
return MdcDialogComponent;
}(MDCComponent));
/**
* @fileoverview added by tsickle
* Generated from: dialog/dialog-config.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @template D
*/
var /**
* @template D
*/
MdcDialogConfig = /** @class */ (function () {
function MdcDialogConfig() {
/**
* ID of the element that describes the dialog.
*/
this.ariaDescribedBy = null;
/**
* Aria label to assign to the dialog element
*/
this.ariaLabel = null;
/**
* Whether the user can use escape key to close the dialog
*/
this.escapeToClose = true;
/**
* Whether the user can click outside to close the dialog
*/
this.clickOutsideToClose = true;
/**
* Applied automatically when the dialog has overflowing content to warrant scrolling.
*/
this.scrollable = true;
/**
* Applied automatically when the dialog's action buttons can't fit on a single line and must be stacked.
*/
this.buttonsStacked = true;
/**
* Whether the dialog should focus the first focusable element on open.
*/
this.autoFocus = true;
/**
* Whether the dialog should restore focus to the
* previously-focused element, after it's closed.
*/
this.restoreFocus = true;
/**
* Data to be injected into the dialog content.
*/
this.data = null;
}
return MdcDialogConfig;
}());
/**
* @fileoverview added by tsickle
* Generated from: dialog/dialog-portal.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Throws an exception for the case when a ComponentPortal is
* attached to a DomPortalOutlet without an origin.
* @return {?}
*/
function throwMdcDialogContentAlreadyAttachedError() {
throw Error('Attempting to attach dialog content after content is already attached');
}
var MdcDialogPortal = /** @class */ (function (_super) {
__extends(MdcDialogPortal, _super);
function MdcDialogPortal(_elementRef, _focusTrapFactory, _document, _config) {
var _this = _super.call(this) || this;
_this._elementRef = _elementRef;
_this._focusTrapFactory = _focusTrapFactory;
_this._document = _document;
_this._config = _config;
/**
* Element that was focused before the dialog was opened. Save this to restore upon close.
*/
_this._elementFocusedBeforeDialogWasOpened = null;
/**
* A subject emitting after the dialog exits the view.
*/
_this._afterExit = new Subject();
return _this;
}
/**
* Attach a ComponentPortal as content to this dialog container.
* @param portal Portal to be attached as the dialog content.
*/
/**
* Attach a ComponentPortal as content to this dialog container.
* @template T
* @param {?} portal Portal to be attached as the dialog content.
* @return {?}
*/
MdcDialogPortal.prototype.attachComponentPortal = /**
* Attach a ComponentPortal as content to this dialog container.
* @template T
* @param {?} portal Portal to be attached as the dialog content.
* @return {?}
*/
function (portal) {
if (this._portalOutlet.hasAttached()) {
throwMdcDialogContentAlreadyAttachedError();
}
this._savePreviouslyFocusedElement();
return this._portalOutlet.attachComponentPortal(portal);
};
/**
* Attach a TemplatePortal as content to this dialog container.
* @param portal Portal to be attached as the dialog content.
*/
/**
* Attach a TemplatePortal as content to this dialog container.
* @template C
* @param {?} portal Portal to be attached as the dialog content.
* @return {?}
*/
MdcDialogPortal.prototype.attachTemplatePortal = /**
* Attach a TemplatePortal as content to this dialog container.
* @template C
* @param {?} portal Portal to be attached as the dialog content.
* @return {?}
*/
function (portal) {
if (this._portalOutlet.hasAttached()) {
throwMdcDialogContentAlreadyAttachedError();
}
this._savePreviouslyFocusedElement();
return this._portalOutlet.attachTemplatePortal(portal);
};
/** Moves the focus inside the focus trap. */
/**
* Moves the focus inside the focus trap.
* @return {?}
*/
MdcDialogPortal.prototype.trapFocus = /**
* Moves the focus inside the focus trap.
* @return {?}
*/
function () {
/** @type {?} */
var element = this._elementRef.nativeElement;
if (!this._focusTrap) {
this._focusTrap = this._focusTrapFactory.create(element);
}
// If we 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.
if (this._config.autoFocus) {
this._focusTrap.focusInitialElementWhenReady();
}
else {
/** @type {?} */
var activeElement = this._document.activeElement;
// Otherwise ensure that focus is on the dialog container. It's possible that a different
// component tried to move focus. Note that we only want to do this
// if the focus isn't inside the dialog already, because it's possible that the consumer
// turned off `autoFocus` in order to move focus themselves.
if (activeElement !== element && !element.contains(activeElement)) {
element.focus();
}
}
};
/** Restores focus to the element that was focused before the dialog opened. */
/**
* Restores focus to the element that was focused before the dialog opened.
* @return {?}
*/
MdcDialogPortal.prototype.restoreFocus = /**
* Restores focus to the element that was focused before the dialog opened.
* @return {?}
*/
function () {
/** @type {?} */
var toFocus = this._elementFocusedBeforeDialogWasOpened;
// We need the extra check, because IE can set the `activeElement` to null in some cases.
if (this._config.restoreFocus && toFocus && typeof toFocus.focus === 'function') {
toFocus.focus();
}
if (this._focusTrap) {
this._focusTrap.destroy();
}
};
/** Saves a reference to the element that was focused before the dialog was opened. */
/**
* Saves a reference to the element that was focused before the dialog was opened.
* @private
* @return {?}
*/
MdcDialogPortal.prototype._savePreviouslyFocusedElement = /**
* Saves a reference to the element that was focused before the dialog was opened.
* @private
* @return {?}
*/
function () {
var _this = this;
if (this._document) {
this._elementFocusedBeforeDialogWasOpened = (/** @type {?} */ (this._document.activeElement));
// Note that there is no focus method when rendering on the server.
if (this._elementRef.nativeElement.focus) {
// Move focus onto the dialog immediately in order to prevent the user from accidentally
// opening multiple dialogs at the same time. Needs to be async, because the element
// may not be focusable immediately.
Promise.resolve().then((/**
* @return {?}
*/
function () { return _this._elementRef.nativeElement.focus(); }));
}
}
};
MdcDialogPortal.decorators = [
{ type: Component, args: [{selector: 'mdc-dialog-portal',
host: {
'[attr.id]': '_id'
},
template: '<ng-template cdkPortalOutlet></ng-template>',
encapsulation: ViewEncapsulation.None
},] },
];
/** @nocollapse */
MdcDialogPortal.ctorParameters = function () { return [
{ type: ElementRef },
{ type: FocusTrapFactory },
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [DOCUMENT,] }] },
{ type: MdcDialogConfig }
]; };
MdcDialogPortal.propDecorators = {
_portalOutlet: [{ type: ViewChild, args: [CdkPortalOutlet, { static: true },] }]
};
return MdcDialogPortal;
}(BasePortalOutlet));
/**
* @fileoverview added by tsickle
* Generated from: dialog/dialog.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Injection token that can be used to access the data that was passed in to a dialog.
* @type {?}
*/
var MDC_DIALOG_DATA = new InjectionToken('MdcDialogData');
/**
* Injection token that can be used to specify default dialog options.
* @type {?}
*/
var MDC_DIALOG_DEFAULT_OPTIONS = new InjectionToken('mdc-dialog-default-options');
var MdcDialog = /** @class */ (function () {
function MdcDialog(_overlay, _injector, _defaultOptions, _parentDialog) {
var _this = this;
this._overlay = _overlay;
this._injector = _injector;
this._defaultOptions = _defaultOptions;
this._parentDialog = _parentDialog;
this._openDialogsAtThisLevel = [];
this._afterAllClosedAtThisLevel = new Subject();
this._afterOpenedAtThisLevel = new Subject();
this._ariaHiddenElements = new Map();
/**
* Stream that emits when all open dialog have finished closing.
* Will emit on subscribe if there are no open dialogs to begin with.
*/
this.afterAllClosed = (/** @type {?} */ (defer((/**
* @return {?}
*/
function () { return _this.openDialogs.length ?
_this._afterAllClosed :
_this._afterAllClosed.pipe(startWith(undefined)); }))));
}
Object.defineProperty(MdcDialog.prototype, "openDialogs", {
/** Keeps track of the currently-open dialogs. */
get: /**
* Keeps track of the currently-open dialogs.
* @return {?}
*/
function () {
return this._parentDialog ? this._parentDialog.openDialogs : this._openDialogsAtThisLevel;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MdcDialog.prototype, "afterOpened", {
/** Stream that emits when a dialog has been opened. */
get: /**
* Stream that emits when a dialog has been opened.
* @return {?}
*/
function () {
return this._parentDialog ? this._parentDialog.afterOpened : this._afterOpenedAtThisLevel;
},
enumerable: true,
configurable: true
});
Object.defineProperty(MdcDialog.prototype, "_afterAllClosed", {
get: /**
* @return {?}
*/
function () {
/** @type {?} */
var parent = this._parentDialog;
return parent ? parent._afterAllClosed : this._afterAllClosedAtThisLevel;
},
enumerable: true,
configurable: true
});
/**
* Opens a modal dialog containing the given template.
* @param componentOrTemplateRef Type of the component to load into the dialog,
* or a TemplateRef to instantiate as the dialog content.
* @param config Extra configuration options.
* @returns Reference to the newly-opened dialog.
*/
/**
* Opens a modal dialog containing the given template.
* @template T, D, R
* @param {?} componentOrTemplateRef Type of the component to load into the dialog,
* or a TemplateRef to instantiate as the dialog content.
* @param {?=} config Extra configuration options.
* @return {?} Reference to the newly-opened dialog.
*/
MdcDialog.prototype.open = /**
* Opens a modal dialog containing the given template.
* @template T, D, R
* @param {?} componentOrTemplateRef Type of the component to load into the dialog,
* or a TemplateRef to instantiate as the dialog content.
* @param {?=} config Extra configuration options.
* @return {?} Reference to the newly-opened dialog.
*/
function (componentOrTemplateRef, config) {
var _this = this;
config = _applyConfigDefaults(config, this._defaultOptions || new MdcDialogConfig());
if (config.id && this.getDialogById(config.id)) {
throw Error("Dialog with id \"" + config.id + "\" exists already. The dialog id must be unique.");
}
/** @type {?} */
var overlayRef = this._createOverlay();
/** @type {?} */
var dialogContainer = this._attachDialogContainer(overlayRef, config);
/** @type {?} */
var dialogRef = this._attachDialogContent(componentOrTemplateRef, dialogContainer, overlayRef, config);
this.openDialogs.push(dialogRef);
dialogRef.afterClosed().subscribe((/**
* @return {?}
*/
function () { return _this._removeOpenDialog(dialogRef, dialogContainer); }));
this.afterOpened.next(dialogRef);
return dialogRef;
};
/** Closes all of the currently-open dialogs. */
/**
* Closes all of the currently-open dialogs.
* @return {?}
*/
MdcDialog.prototype.closeAll = /**
* Closes all of the currently-open dialogs.
* @return {?}
*/
function () {
this._closeDialogs(this.openDialogs);
};
/**
* Finds an open dialog by its id.
* @param id ID to use when looking up the dialog.
*/
/**
* Finds an open dialog by its id.
* @param {?} id ID to use when looking up the dialog.
* @return {?}
*/
MdcDialog.prototype.getDialogById = /**
* Finds an open dialog by its id.
* @param {?} id ID to use when looking up the dialog.
* @return {?}
*/
function (id) {
return this.openDialogs.find((/**
* @param {?} dialog
* @return {?}
*/
function (dialog) { return dialog.id === id; }));
};
/**
* @return {?}
*/
MdcDialog.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
// Only close the dialogs at this level on destroy
// since the parent service may still be active.
this._closeDialogs(this._openDialogsAtThisLevel);
this._afterAllClosedAtThisLevel.complete();
this._afterOpenedAtThisLevel.complete();
};
/**
* Creates the overlay into which the dialog will be loaded.
* @returns A promise resolving to the OverlayRef for the created overlay.
*/
/**
* Creates the overlay into which the dialog will be loaded.
* @private
* @return {?} A promise resolving to the OverlayRef for the created overlay.
*/
MdcDialog.prototype._createOverlay = /**
* Creates the overlay into which the dialog will be loaded.
* @private
* @return {?} A promise resolving to the OverlayRef for the created overlay.
*/
function () {
return this._overlay.create();
};
/**
* Attaches an MdcDialogPortal to a dialog's already-created overlay.
* @param overlay Reference to the dialog's underlying overlay.
* @param config The dialog configuration.
* @returns A promise resolving to a ComponentRef for the attached container.
*/
/**
* Attaches an MdcDialogPortal to a dialog's already-created overlay.
* @private
* @param {?} overlay Reference to the dialog's underlying overlay.
* @param {?} config The dialog configuration.
* @return {?} A promise resolving to a ComponentRef for the attached container.
*/
MdcDialog.prototype._attachDialogContainer = /**
* Attaches an MdcDialogPortal to a dialog's already-created overlay.
* @private
* @param {?} overlay Reference to the dialog's underlying overlay.
* @param {?} config The dialog configuration.
* @return {?} A promise resolving to a ComponentRef for the attached container.
*/
function (overlay, config) {
/** @type {?} */
var userInjector = config && config.viewContainerRef && config.viewContainerRef.injector;
/** @type {?} */
var injector = new PortalInjector(userInjector || this._injector, new WeakMap([
[MdcDialogConfig, config]
]));
/** @type {?} */
var containerPortal = new ComponentPortal(MdcDialogPortal, config.viewContainerRef, injector, config.componentFactoryResolver);
/** @type {?} */
var containerRef = overlay.attach(containerPortal);
return containerRef.instance;
};
/**
* Attaches the user-provided component to the already-created MdcDialogPortal.
* @param componentOrTemplateRef The type of component being loaded into the dialog,
* or a TemplateRef to instantiate as the content.
* @param dialogContainer Reference to the wrapping MdcDialogPortal.
* @param overlayRef Reference to the overlay in which the dialog resides.
* @param config The dialog configuration.
* @returns A promise resolving to the MdcDialogRef that should be returned to the user.
*/
/**
* Attaches the user-provided component to the already-created MdcDialogPortal.
* @private
* @template T, R
* @param {?} componentOrTemplateRef The type of component being loaded into the dialog,
* or a TemplateRef to instantiate as the content.
* @param {?} dialogContainer Reference to the wrapping MdcDialogPortal.
* @param {?} overlayRef Reference to the overlay in which the dialog resides.
* @param {?} config The dialog configuration.
* @return {?} A promise resolving to the MdcDialogRef that should be returned to the user.
*/
MdcDialog.prototype._attachDialogContent = /**
* Attaches the user-provided component to the already-created MdcDialogPortal.
* @private
* @template T, R
* @param {?} componentOrTemplateRef The type of component being loaded into the dialog,
* or a TemplateRef to instantiate as the content.
* @param {?} dialogContainer Reference to the wrapping MdcDialogPortal.
* @param {?} overlayRef Reference to the overlay in which the dialog resides.
* @param {?} config The dialog configuration.
* @return {?} A promise resolving to the MdcDialogRef that should be returned to the user.
*/
function (componentOrTemplateRef, dialogContainer, overlayRef, config) {
// Create a reference to the dialog we're creating in order to give the user a handle
// to modify and close it.
/** @type {?} */
var dialogRef = new MdcDialogRef(overlayRef, dialogContainer, config.id);
if (componentOrTemplateRef instanceof TemplateRef) {
dialogContainer.attachTemplatePortal(new TemplatePortal(componentOrTemplateRef, (/** @type {?} */ (null)), (/** @type {?} */ ({ $implicit: config.data, dialogRef: dialogRef }))));
}
else {
/** @type {?} */
var injector = this._createInjector(config, dialogRef, dialogContainer);
/** @type {?} */
var contentRef = dialogContainer.attachComponentPortal(new ComponentPortal(componentOrTemplateRef, config.viewContainerRef, injector));
dialogRef.componentInstance = contentRef.instance;
}
return dialogRef;
};
/**
* Creates a custom injector to be used inside the dialog. This allows a component loaded inside
* of a dialog to close itself and, optionally, to return a value.
* @param config Config object that is used to construct the dialog.
* @param dialogRef Reference to the dialog.
* @param container Dialog container element that wraps all of the contents.
* @returns The custom injector that can be used inside the dialog.
*/
/**
* Creates a custom injector to be used inside the dialog. This allows a component loaded inside
* of a dialog to close itself and, optionally, to return a value.
* @private
* @template T
* @param {?} config Config object that is used to construct the dialog.
* @param {?} dialogRef Reference to the dialog.
* @param {?} portalContainer
* @return {?} The custom injector that can be used inside the dialog.
*/
MdcDialog.prototype._createInjector = /**
* Creates a custom injector to be used inside the dialog. This allows a component loaded inside
* of a dialog to close itself and, optionally, to return a value.
* @private
* @template T
* @param {?} config Config object that is used to construct the dialog.
* @param {?} dialogRef Reference to the dialog.
* @param {?} portalContainer
* @return {?} The custom injector that can be used inside the dialog.
*/
function (config, dialogRef, portalContainer) {
/** @type {?} */
var userInjector = config && config.viewContainerRef && config.viewContainerRef.injector;
portalContainer.trapFocus();
// The MdcDialogPortal is injected in the portal as the MdcDialogPortal and the dialog's
// content are created out of the same ViewContainerRef and as such, are siblings for injector
// purposes. To allow the hierarchy that is expected, the MdcDialogPortal is explicitly
// added to the injection tokens.
/** @type {?} */
var injectionTokens = new WeakMap([
[MdcDialogPortal, portalContainer],
[MDC_DIALOG_DATA, config.data],
[MdcDialogRef, dialogRef]
]);
return new PortalInjector(userInjector || this._injector, injectionTokens);
};
/**
* Removes a dialog from the array of open dialogs.
* @param dialogRef Dialog to be removed.
*/
/**
* Removes a dialog from the array of open dialogs.
* @private
* @param {?} dialogRef Dialog to be removed.
* @param {?} dialogContainer
* @return {?}
*/
MdcDialog.prototype._removeOpenDialog = /**
* Removes a dialog from the array of open dialogs.
* @private
* @param {?} dialogRef Dialog to be removed.
* @param {?} dialogContainer
* @return {?}
*/
function (dialogRef, dialogContainer) {
/** @type {?} */
var index = this.openDialogs.indexOf(dialogRef);
if (index > -1) {
dialogContainer.restoreFocus();
this.openDialogs.splice(index, 1);
// If all the dialogs were closed, remove/restore the `aria-hidden`
// to a the siblings and emit to the `afterAllClosed` stream.
if (!this.openDialogs.length) {
this._ariaHiddenElements.forEach((/**
* @param {?} previousValue
* @param {?} element
* @return {?}
*/
function (previousValue, element) {
if (previousValue) {
element.setAttribute('aria-hidden', previousValue);
}
else {
element.removeAttribute('aria-hidden');
}
}));
this._ariaHiddenElements.clear();
this._afterAllClosed.next();
}
}
};
/** Closes all of the dialogs in an array. */
/**
* Closes all of the dialogs in an array.
* @private
* @param {?} dialogs
* @return {?}
*/
MdcDialog.prototype._closeDialogs = /**
* Closes all of the dialogs in an array.
* @private
* @param {?} dialogs
* @return {?}
*/
function (dialogs) {
/** @type {?} */
var i = dialogs.length;
while (i--) {
// The `_openDialogs` property isn't updated after close until the rxjs subscription
// runs on the next microtask, in addition to modifying the array as we're going
// through it. We loop through all of them and call close without assuming that
// they'll be removed from the list instantaneously.
dialogs[i].close();
}
};
MdcDialog.decorators = [
{ type: Injectable },
];
/** @nocollapse */
MdcDialog.ctorParameters = function () { return [
{ type: Overlay },
{ type: Injector },
{ type: MdcDialogConfig, decorators: [{ type: Optional }, { type: Inject, args: [MDC_DIALOG_DEFAULT_OPTIONS,] }] },
{ type: MdcDialog, decorators: [{ type: Optional }, { type: SkipSelf }] }
]; };
return MdcDialog;
}());
/**
* Applies default options to the dialog config.
* @param {?=} config Config to be modified.
* @param {?=} defaultOptions Default options provided.
* @return {?} The new configuration object.
*/
function _applyConfigDefaults(config, defaultOptions) {
return __assign(__assign({}, defaultOptions), config);
}
/**
* @fileoverview added by tsickle
* Generated from: dialog/module.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
var DIALOG_DECLARATIONS = [
MdcDialogAction,
MdcDialogActions,
MdcDialogButton,
MdcDialogComponent,
MdcDialogContainer,
MdcDialogPortal,
MdcDialogContent,
MdcDialogScrim,
MdcDialogSurface,
MdcDialogSurface,
MdcDialogTitle
];
var MdcDialogModule = /** @class */ (function () {
function MdcDialogModule() {
}
MdcDialogModule.decorators = [
{ type: NgModule, args: [{
imports: [
OverlayModule,
PortalModule
],
exports: DIALOG_DECLARATIONS,
declarations: DIALOG_DECLARATIONS,
providers: [MdcDialog],