UNPKG

@angular/material

Version:
1,224 lines (1,218 loc) 921 kB
/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/core'), require('@angular/platform-browser'), require('rxjs/Subject'), require('rxjs/add/operator/debounceTime'), require('@angular/common'), require('rxjs/Observable'), require('rxjs/Subscription'), require('rxjs/add/observable/fromEvent'), require('rxjs/add/observable/merge'), require('rxjs/add/operator/auditTime'), require('rxjs/add/operator/first'), require('rxjs/add/observable/of'), require('@angular/forms'), require('@angular/animations'), require('rxjs/add/operator/startWith'), require('rxjs/add/operator/filter'), require('@angular/http'), require('rxjs/add/observable/forkJoin'), require('rxjs/add/operator/map'), require('rxjs/add/operator/do'), require('rxjs/add/operator/share'), require('rxjs/add/operator/finally'), require('rxjs/add/operator/catch'), require('rxjs/add/observable/throw'), require('rxjs/add/operator/takeUntil'), require('rxjs/add/operator/switchMap')) : typeof define === 'function' && define.amd ? define(['exports', '@angular/core', '@angular/platform-browser', 'rxjs/Subject', 'rxjs/add/operator/debounceTime', '@angular/common', 'rxjs/Observable', 'rxjs/Subscription', 'rxjs/add/observable/fromEvent', 'rxjs/add/observable/merge', 'rxjs/add/operator/auditTime', 'rxjs/add/operator/first', 'rxjs/add/observable/of', '@angular/forms', '@angular/animations', 'rxjs/add/operator/startWith', 'rxjs/add/operator/filter', '@angular/http', 'rxjs/add/observable/forkJoin', 'rxjs/add/operator/map', 'rxjs/add/operator/do', 'rxjs/add/operator/share', 'rxjs/add/operator/finally', 'rxjs/add/operator/catch', 'rxjs/add/observable/throw', 'rxjs/add/operator/takeUntil', 'rxjs/add/operator/switchMap'], factory) : (factory((global.ng = global.ng || {}, global.ng.material = global.ng.material || {}),global.ng.core,global.ng.platformBrowser,global.Rx,global.Rx.Observable.prototype,global.ng.common,global.Rx,global.Rx,global.Rx.Observable,global.Rx.Observable,global.Rx.Observable.prototype,global.Rx.Observable.prototype,global.Rx.Observable,global.ng.forms,global.ng.animations,global.Rx.Observable.prototype,global.Rx.Observable.prototype,global.ng.http)); }(this, (function (exports,_angular_core,_angular_platformBrowser,rxjs_Subject,rxjs_add_operator_debounceTime,_angular_common,rxjs_Observable,rxjs_Subscription,rxjs_add_observable_fromEvent,rxjs_add_observable_merge,rxjs_add_operator_auditTime,rxjs_add_operator_first,rxjs_add_observable_of,_angular_forms,_angular_animations,rxjs_add_operator_startWith,rxjs_add_operator_filter,_angular_http) { 'use strict'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var MATERIAL_COMPATIBILITY_MODE = new _angular_core.InjectionToken('md-compatibility-mode'); /** * Returns an exception to be thrown if the consumer has used * an invalid Material prefix on a component. * \@docs-private * @param {?} prefix * @param {?} nodeName * @return {?} */ function getMdCompatibilityInvalidPrefixError(prefix, nodeName) { return Error("The \"" + prefix + "-\" prefix cannot be used in ng-material v1 compatibility mode. " + ("It was used on an \"" + nodeName.toLowerCase() + "\" element.")); } /** * Selector that matches all elements that may have style collisions with AngularJS Material. */ var MAT_ELEMENTS_SELECTOR = "\n [mat-button],\n [mat-fab],\n [mat-icon-button],\n [mat-mini-fab],\n [mat-raised-button],\n [matCardSubtitle],\n [matCardTitle],\n [matDialogActions],\n [matDialogClose],\n [matDialogContent],\n [matDialogTitle],\n [matLine],\n [matTabLabel],\n [matTabLink],\n [matTabNav],\n [matTooltip],\n mat-autocomplete,\n mat-button-toggle,\n mat-button-toggle,\n mat-button-toggle-group,\n mat-card,\n mat-card-actions,\n mat-card-content,\n mat-card-footer,\n mat-card-header,\n mat-card-subtitle,\n mat-card-title,\n mat-card-title-group,\n mat-checkbox,\n mat-chip,\n mat-dialog-actions,\n mat-dialog-container,\n mat-dialog-content,\n mat-divider,\n mat-error,\n mat-grid-list,\n mat-grid-tile,\n mat-grid-tile-footer,\n mat-grid-tile-header,\n mat-hint,\n mat-icon,\n mat-list,\n mat-list-item,\n mat-menu,\n mat-nav-list,\n mat-option,\n mat-placeholder,\n mat-progress-bar,\n mat-pseudo-checkbox,\n mat-radio-button,\n mat-radio-group,\n mat-select,\n mat-sidenav,\n mat-sidenav-container,\n mat-slider,\n mat-spinner,\n mat-tab,\n mat-tab-group,\n mat-toolbar"; /** * Selector that matches all elements that may have style collisions with AngularJS Material. */ var MD_ELEMENTS_SELECTOR = "\n [md-button],\n [md-fab],\n [md-icon-button],\n [md-mini-fab],\n [md-raised-button],\n [mdCardSubtitle],\n [mdCardTitle],\n [mdDialogActions],\n [mdDialogClose],\n [mdDialogContent],\n [mdDialogTitle],\n [mdLine],\n [mdTabLabel],\n [mdTabLink],\n [mdTabNav],\n [mdTooltip],\n md-autocomplete,\n md-button-toggle,\n md-button-toggle,\n md-button-toggle-group,\n md-card,\n md-card-actions,\n md-card-content,\n md-card-footer,\n md-card-header,\n md-card-subtitle,\n md-card-title,\n md-card-title-group,\n md-checkbox,\n md-chip,\n md-dialog-actions,\n md-dialog-container,\n md-dialog-content,\n md-divider,\n md-error,\n md-grid-list,\n md-grid-tile,\n md-grid-tile-footer,\n md-grid-tile-header,\n md-hint,\n md-icon,\n md-list,\n md-list-item,\n md-menu,\n md-nav-list,\n md-option,\n md-placeholder,\n md-progress-bar,\n md-pseudo-checkbox,\n md-radio-button,\n md-radio-group,\n md-select,\n md-sidenav,\n md-sidenav-container,\n md-slider,\n md-spinner,\n md-tab,\n md-tab-group,\n md-toolbar"; /** * Directive that enforces that the `mat-` prefix cannot be used. */ var MatPrefixRejector = (function () { /** * @param {?} isCompatibilityMode * @param {?} elementRef */ function MatPrefixRejector(isCompatibilityMode, elementRef) { if (!isCompatibilityMode) { throw getMdCompatibilityInvalidPrefixError('mat', elementRef.nativeElement.nodeName); } } return MatPrefixRejector; }()); MatPrefixRejector.decorators = [ { type: _angular_core.Directive, args: [{ selector: MAT_ELEMENTS_SELECTOR },] }, ]; /** * @nocollapse */ MatPrefixRejector.ctorParameters = function () { return [ { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [MATERIAL_COMPATIBILITY_MODE,] },] }, { type: _angular_core.ElementRef, }, ]; }; /** * Directive that enforces that the `md-` prefix cannot be used. */ var MdPrefixRejector = (function () { /** * @param {?} isCompatibilityMode * @param {?} elementRef */ function MdPrefixRejector(isCompatibilityMode, elementRef) { if (isCompatibilityMode) { throw getMdCompatibilityInvalidPrefixError('md', elementRef.nativeElement.nodeName); } } return MdPrefixRejector; }()); MdPrefixRejector.decorators = [ { type: _angular_core.Directive, args: [{ selector: MD_ELEMENTS_SELECTOR },] }, ]; /** * @nocollapse */ MdPrefixRejector.ctorParameters = function () { return [ { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [MATERIAL_COMPATIBILITY_MODE,] },] }, { type: _angular_core.ElementRef, }, ]; }; /** * Module that enforces the default compatibility mode settings. When this module is loaded * without NoConflictStyleCompatibilityMode also being imported, it will throw an error if * there are any uses of the `mat-` prefix. */ var CompatibilityModule = (function () { function CompatibilityModule() { } return CompatibilityModule; }()); CompatibilityModule.decorators = [ { type: _angular_core.NgModule, args: [{ declarations: [MatPrefixRejector, MdPrefixRejector], exports: [MatPrefixRejector, MdPrefixRejector], },] }, ]; /** * @nocollapse */ CompatibilityModule.ctorParameters = function () { return []; }; /** * Module that enforces "no-conflict" compatibility mode settings. When this module is loaded, * it will throw an error if there are any uses of the `md-` prefix. */ var NoConflictStyleCompatibilityMode = (function () { function NoConflictStyleCompatibilityMode() { } return NoConflictStyleCompatibilityMode; }()); NoConflictStyleCompatibilityMode.decorators = [ { type: _angular_core.NgModule, args: [{ providers: [{ provide: MATERIAL_COMPATIBILITY_MODE, useValue: true, }], },] }, ]; /** * @nocollapse */ NoConflictStyleCompatibilityMode.ctorParameters = function () { return []; }; /** * Injection token that configures whether the Material sanity checks are enabled. */ var MATERIAL_SANITY_CHECKS = new _angular_core.InjectionToken('md-sanity-checks'); /** * Module that captures anything that should be loaded and/or run for *all* Angular Material * components. This includes Bidi, compatibility mode, etc. * * This module should be imported to each top-level component module (e.g., MdTabsModule). */ var MdCommonModule = (function () { /** * @param {?} _document * @param {?} _sanityChecksEnabled */ function MdCommonModule(_document, _sanityChecksEnabled) { this._document = _document; /** * Whether we've done the global sanity checks (e.g. a theme is loaded, there is a doctype). */ this._hasDoneGlobalChecks = false; if (_sanityChecksEnabled && !this._hasDoneGlobalChecks && _document && _angular_core.isDevMode()) { this._checkDoctype(); this._checkTheme(); this._hasDoneGlobalChecks = true; } } /** * @return {?} */ MdCommonModule.prototype._checkDoctype = function () { if (!this._document.doctype) { console.warn('Current document does not have a doctype. This may cause ' + 'some Angular Material components not to behave as expected.'); } }; /** * @return {?} */ MdCommonModule.prototype._checkTheme = function () { if (typeof getComputedStyle === 'function') { var /** @type {?} */ testElement = this._document.createElement('div'); testElement.classList.add('mat-theme-loaded-marker'); this._document.body.appendChild(testElement); if (getComputedStyle(testElement).display !== 'none') { console.warn('Could not find Angular Material core theme. Most Material ' + 'components may not work as expected. For more info refer ' + 'to the theming guide: https://material.angular.io/guide/theming'); } this._document.body.removeChild(testElement); } }; return MdCommonModule; }()); MdCommonModule.decorators = [ { type: _angular_core.NgModule, args: [{ imports: [CompatibilityModule], exports: [CompatibilityModule], providers: [{ provide: MATERIAL_SANITY_CHECKS, useValue: true, }], },] }, ]; /** * @nocollapse */ MdCommonModule.ctorParameters = function () { return [ { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [_angular_platformBrowser.DOCUMENT,] },] }, { type: undefined, decorators: [{ type: _angular_core.Optional }, { type: _angular_core.Inject, args: [MATERIAL_SANITY_CHECKS,] },] }, ]; }; /** * Shared directive to count lines inside a text area, such as a list item. * Line elements can be extracted with a \@ContentChildren(MdLine) query, then * counted by checking the query list's length. */ var MdLine = (function () { function MdLine() { } return MdLine; }()); MdLine.decorators = [ { type: _angular_core.Directive, args: [{ selector: '[md-line], [mat-line], [mdLine], [matLine]', host: { 'class': 'mat-line' } },] }, ]; /** * @nocollapse */ MdLine.ctorParameters = function () { return []; }; /** * Helper that takes a query list of lines and sets the correct class on the host. * \@docs-private */ var MdLineSetter = (function () { /** * @param {?} _lines * @param {?} _renderer * @param {?} _element */ function MdLineSetter(_lines, _renderer, _element) { var _this = this; this._lines = _lines; this._renderer = _renderer; this._element = _element; this._setLineClass(this._lines.length); this._lines.changes.subscribe(function () { _this._setLineClass(_this._lines.length); }); } /** * @param {?} count * @return {?} */ MdLineSetter.prototype._setLineClass = function (count) { this._resetClasses(); if (count === 2 || count === 3) { this._setClass("mat-" + count + "-line", true); } else if (count > 3) { this._setClass("mat-multi-line", true); } }; /** * @return {?} */ MdLineSetter.prototype._resetClasses = function () { this._setClass('mat-2-line', false); this._setClass('mat-3-line', false); this._setClass('mat-multi-line', false); }; /** * @param {?} className * @param {?} isAdd * @return {?} */ MdLineSetter.prototype._setClass = function (className, isAdd) { if (isAdd) { this._renderer.addClass(this._element.nativeElement, className); } else { this._renderer.removeClass(this._element.nativeElement, className); } }; return MdLineSetter; }()); var MdLineModule = (function () { function MdLineModule() { } return MdLineModule; }()); MdLineModule.decorators = [ { type: _angular_core.NgModule, args: [{ imports: [MdCommonModule], exports: [MdLine, MdCommonModule], declarations: [MdLine], },] }, ]; /** * @nocollapse */ MdLineModule.ctorParameters = function () { return []; }; /** * Directive to listen for changes of direction of part of the DOM. * * Applications should use this directive instead of the native attribute so that Material * components can listen on changes of direction. */ var Dir = (function () { function Dir() { /** * Layout direction of the element. */ this._dir = 'ltr'; /** * Event emitted when the direction changes. */ this.dirChange = new _angular_core.EventEmitter(); } Object.defineProperty(Dir.prototype, "dir", { /** * \@docs-private * @return {?} */ get: function () { return this._dir; }, /** * @param {?} v * @return {?} */ set: function (v) { var /** @type {?} */ old = this._dir; this._dir = v; if (old != this._dir) { this.dirChange.emit(); } }, enumerable: true, configurable: true }); Object.defineProperty(Dir.prototype, "value", { /** * Current layout direction of the element. * @return {?} */ get: function () { return this.dir; }, /** * @param {?} v * @return {?} */ set: function (v) { this.dir = v; }, enumerable: true, configurable: true }); return Dir; }()); Dir.decorators = [ { type: _angular_core.Directive, args: [{ selector: '[dir]', // TODO(hansl): maybe `$implicit` isn't the best option here, but for now that's the best we got. exportAs: '$implicit' },] }, ]; /** * @nocollapse */ Dir.ctorParameters = function () { return []; }; Dir.propDecorators = { '_dir': [{ type: _angular_core.Input, args: ['dir',] },], 'dirChange': [{ type: _angular_core.Output },], 'dir': [{ type: _angular_core.HostBinding, args: ['attr.dir',] },], }; var RtlModule = (function () { function RtlModule() { } return RtlModule; }()); RtlModule.decorators = [ { type: _angular_core.NgModule, args: [{ exports: [Dir], declarations: [Dir] },] }, ]; /** * @nocollapse */ RtlModule.ctorParameters = function () { return []; }; /** * Factory that creates a new MutationObserver and allows us to stub it out in unit tests. * \@docs-private */ var MdMutationObserverFactory = (function () { function MdMutationObserverFactory() { } /** * @param {?} callback * @return {?} */ MdMutationObserverFactory.prototype.create = function (callback) { return typeof MutationObserver === 'undefined' ? null : new MutationObserver(callback); }; return MdMutationObserverFactory; }()); MdMutationObserverFactory.decorators = [ { type: _angular_core.Injectable }, ]; /** * @nocollapse */ MdMutationObserverFactory.ctorParameters = function () { return []; }; /** * Directive that triggers a callback whenever the content of * its associated element has changed. */ var ObserveContent = (function () { /** * @param {?} _mutationObserverFactory * @param {?} _elementRef */ function ObserveContent(_mutationObserverFactory, _elementRef) { this._mutationObserverFactory = _mutationObserverFactory; this._elementRef = _elementRef; /** * Event emitted for each change in the element's content. */ this.event = new _angular_core.EventEmitter(); /** * Used for debouncing the emitted values to the observeContent event. */ this._debouncer = new rxjs_Subject.Subject(); } /** * @return {?} */ ObserveContent.prototype.ngAfterContentInit = function () { var _this = this; if (this.debounce > 0) { this._debouncer .debounceTime(this.debounce) .subscribe(function (mutations) { return _this.event.emit(mutations); }); } else { this._debouncer.subscribe(function (mutations) { return _this.event.emit(mutations); }); } this._observer = this._mutationObserverFactory.create(function (mutations) { _this._debouncer.next(mutations); }); if (this._observer) { this._observer.observe(this._elementRef.nativeElement, { characterData: true, childList: true, subtree: true }); } }; /** * @return {?} */ ObserveContent.prototype.ngOnDestroy = function () { if (this._observer) { this._observer.disconnect(); this._debouncer.complete(); this._debouncer = this._observer = null; } }; return ObserveContent; }()); ObserveContent.decorators = [ { type: _angular_core.Directive, args: [{ selector: '[cdkObserveContent]' },] }, ]; /** * @nocollapse */ ObserveContent.ctorParameters = function () { return [ { type: MdMutationObserverFactory, }, { type: _angular_core.ElementRef, }, ]; }; ObserveContent.propDecorators = { 'event': [{ type: _angular_core.Output, args: ['cdkObserveContent',] },], 'debounce': [{ type: _angular_core.Input },], }; var ObserveContentModule = (function () { function ObserveContentModule() { } return ObserveContentModule; }()); ObserveContentModule.decorators = [ { type: _angular_core.NgModule, args: [{ exports: [ObserveContent], declarations: [ObserveContent], providers: [MdMutationObserverFactory] },] }, ]; /** * @nocollapse */ ObserveContentModule.ctorParameters = function () { return []; }; var RippleState = {}; RippleState.FADING_IN = 0; RippleState.VISIBLE = 1; RippleState.FADING_OUT = 2; RippleState.HIDDEN = 3; RippleState[RippleState.FADING_IN] = "FADING_IN"; RippleState[RippleState.VISIBLE] = "VISIBLE"; RippleState[RippleState.FADING_OUT] = "FADING_OUT"; RippleState[RippleState.HIDDEN] = "HIDDEN"; /** * Reference to a previously launched ripple element. */ var RippleRef = (function () { /** * @param {?} _renderer * @param {?} element * @param {?} config */ function RippleRef(_renderer, element, config) { this._renderer = _renderer; this.element = element; this.config = config; /** * Current state of the ripple reference. */ this.state = RippleState.HIDDEN; } /** * Fades out the ripple element. * @return {?} */ RippleRef.prototype.fadeOut = function () { this._renderer.fadeOutRipple(this); }; return RippleRef; }()); /** * Fade-in duration for the ripples. Can be modified with the speedFactor option. */ var RIPPLE_FADE_IN_DURATION = 450; /** * Fade-out duration for the ripples in milliseconds. This can't be modified by the speedFactor. */ var RIPPLE_FADE_OUT_DURATION = 400; /** * Helper service that performs DOM manipulations. Not intended to be used outside this module. * The constructor takes a reference to the ripple directive's host element and a map of DOM * event handlers to be installed on the element that triggers ripple animations. * This will eventually become a custom renderer once Angular support exists. * \@docs-private */ var RippleRenderer = (function () { /** * @param {?} elementRef * @param {?} _ngZone * @param {?} _ruler * @param {?} platform */ function RippleRenderer(elementRef, _ngZone, _ruler, platform) { this._ngZone = _ngZone; this._ruler = _ruler; /** * Whether the mouse is currently down or not. */ this._isMousedown = false; /** * Events to be registered on the trigger element. */ this._triggerEvents = new Map(); /** * Set of currently active ripple references. */ this._activeRipples = new Set(); /** * Ripple config for all ripples created by events. */ this.rippleConfig = {}; /** * Whether mouse ripples should be created or not. */ this.rippleDisabled = false; // Only do anything if we're on the browser. if (platform.isBrowser) { this._containerElement = elementRef.nativeElement; // Specify events which need to be registered on the trigger. this._triggerEvents.set('mousedown', this.onMousedown.bind(this)); this._triggerEvents.set('mouseup', this.onMouseup.bind(this)); this._triggerEvents.set('mouseleave', this.onMouseLeave.bind(this)); // By default use the host element as trigger element. this.setTriggerElement(this._containerElement); } } /** * Fades in a ripple at the given coordinates. * @param {?} pageX * @param {?} pageY * @param {?=} config * @return {?} */ RippleRenderer.prototype.fadeInRipple = function (pageX, pageY, config) { var _this = this; if (config === void 0) { config = {}; } var /** @type {?} */ containerRect = this._containerElement.getBoundingClientRect(); if (config.centered) { pageX = containerRect.left + containerRect.width / 2; pageY = containerRect.top + containerRect.height / 2; } else { // Subtract scroll values from the coordinates because calculations below // are always relative to the viewport rectangle. var /** @type {?} */ scrollPosition = this._ruler.getViewportScrollPosition(); pageX -= scrollPosition.left; pageY -= scrollPosition.top; } var /** @type {?} */ radius = config.radius || distanceToFurthestCorner(pageX, pageY, containerRect); var /** @type {?} */ duration = RIPPLE_FADE_IN_DURATION * (1 / (config.speedFactor || 1)); var /** @type {?} */ offsetX = pageX - containerRect.left; var /** @type {?} */ offsetY = pageY - containerRect.top; var /** @type {?} */ ripple = document.createElement('div'); ripple.classList.add('mat-ripple-element'); ripple.style.left = offsetX - radius + "px"; ripple.style.top = offsetY - radius + "px"; ripple.style.height = radius * 2 + "px"; ripple.style.width = radius * 2 + "px"; // If the color is not set, the default CSS color will be used. ripple.style.backgroundColor = config.color; ripple.style.transitionDuration = duration + "ms"; this._containerElement.appendChild(ripple); // By default the browser does not recalculate the styles of dynamically created // ripple elements. This is critical because then the `scale` would not animate properly. enforceStyleRecalculation(ripple); ripple.style.transform = 'scale(1)'; // Exposed reference to the ripple that will be returned. var /** @type {?} */ rippleRef = new RippleRef(this, ripple, config); rippleRef.state = RippleState.FADING_IN; // Add the ripple reference to the list of all active ripples. this._activeRipples.add(rippleRef); // Wait for the ripple element to be completely faded in. // Once it's faded in, the ripple can be hidden immediately if the mouse is released. this.runTimeoutOutsideZone(function () { rippleRef.state = RippleState.VISIBLE; if (!config.persistent && !_this._isMousedown) { rippleRef.fadeOut(); } }, duration); return rippleRef; }; /** * Fades out a ripple reference. * @param {?} rippleRef * @return {?} */ RippleRenderer.prototype.fadeOutRipple = function (rippleRef) { // For ripples that are not active anymore, don't re-un the fade-out animation. if (!this._activeRipples.delete(rippleRef)) { return; } var /** @type {?} */ rippleEl = rippleRef.element; rippleEl.style.transitionDuration = RIPPLE_FADE_OUT_DURATION + "ms"; rippleEl.style.opacity = '0'; rippleRef.state = RippleState.FADING_OUT; // Once the ripple faded out, the ripple can be safely removed from the DOM. this.runTimeoutOutsideZone(function () { rippleRef.state = RippleState.HIDDEN; rippleEl.parentNode.removeChild(rippleEl); }, RIPPLE_FADE_OUT_DURATION); }; /** * Fades out all currently active ripples. * @return {?} */ RippleRenderer.prototype.fadeOutAll = function () { this._activeRipples.forEach(function (ripple) { return ripple.fadeOut(); }); }; /** * Sets the trigger element and registers the mouse events. * @param {?} element * @return {?} */ RippleRenderer.prototype.setTriggerElement = function (element) { var _this = this; // Remove all previously register event listeners from the trigger element. if (this._triggerElement) { this._triggerEvents.forEach(function (fn, type) { return _this._triggerElement.removeEventListener(type, fn); }); } if (element) { // If the element is not null, register all event listeners on the trigger element. this._ngZone.runOutsideAngular(function () { _this._triggerEvents.forEach(function (fn, type) { return element.addEventListener(type, fn); }); }); } this._triggerElement = element; }; /** * Listener being called on mousedown event. * @param {?} event * @return {?} */ RippleRenderer.prototype.onMousedown = function (event) { if (!this.rippleDisabled) { this._isMousedown = true; this.fadeInRipple(event.pageX, event.pageY, this.rippleConfig); } }; /** * Listener being called on mouseup event. * @return {?} */ RippleRenderer.prototype.onMouseup = function () { this._isMousedown = false; // Fade-out all ripples that are completely visible and not persistent. this._activeRipples.forEach(function (ripple) { if (!ripple.config.persistent && ripple.state === RippleState.VISIBLE) { ripple.fadeOut(); } }); }; /** * Listener being called on mouseleave event. * @return {?} */ RippleRenderer.prototype.onMouseLeave = function () { if (this._isMousedown) { this.onMouseup(); } }; /** * Runs a timeout outside of the Angular zone to avoid triggering the change detection. * @param {?} fn * @param {?=} delay * @return {?} */ RippleRenderer.prototype.runTimeoutOutsideZone = function (fn, delay) { if (delay === void 0) { delay = 0; } this._ngZone.runOutsideAngular(function () { return setTimeout(fn, delay); }); }; return RippleRenderer; }()); /** * @param {?} element * @return {?} */ function enforceStyleRecalculation(element) { // Enforce a style recalculation by calling `getComputedStyle` and accessing any property. // Calling `getPropertyValue` is important to let optimizers know that this is not a noop. // See: https://gist.github.com/paulirish/5d52fb081b3570c81e3a window.getComputedStyle(element).getPropertyValue('opacity'); } /** * Returns the distance from the point (x, y) to the furthest corner of a rectangle. * @param {?} x * @param {?} y * @param {?} rect * @return {?} */ function distanceToFurthestCorner(x, y, rect) { var /** @type {?} */ distX = Math.max(Math.abs(x - rect.left), Math.abs(x - rect.right)); var /** @type {?} */ distY = Math.max(Math.abs(y - rect.top), Math.abs(y - rect.bottom)); return Math.sqrt(distX * distX + distY * distY); } // Whether the current platform supports the V8 Break Iterator. The V8 check // is necessary to detect all Blink based browsers. var hasV8BreakIterator = (typeof (Intl) !== 'undefined' && ((Intl)).v8BreakIterator); /** * Service to detect the current platform by comparing the userAgent strings and * checking browser-specific global properties. * \@docs-private */ var Platform = (function () { function Platform() { this.isBrowser = typeof document === 'object' && !!document; /** * Layout Engines */ this.EDGE = this.isBrowser && /(edge)/i.test(navigator.userAgent); this.TRIDENT = this.isBrowser && /(msie|trident)/i.test(navigator.userAgent); // EdgeHTML and Trident mock Blink specific things and need to be excluded from this check. this.BLINK = this.isBrowser && (!!(((window)).chrome || hasV8BreakIterator) && !!CSS && !this.EDGE && !this.TRIDENT); // Webkit is part of the userAgent in EdgeHTML, Blink and Trident. Therefore we need to // ensure that Webkit runs standalone and is not used as another engine's base. this.WEBKIT = this.isBrowser && /AppleWebKit/i.test(navigator.userAgent) && !this.BLINK && !this.EDGE && !this.TRIDENT; /** * Browsers and Platform Types */ this.IOS = this.isBrowser && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream; // It's difficult to detect the plain Gecko engine, because most of the browsers identify // them self as Gecko-like browsers and modify the userAgent's according to that. // Since we only cover one explicit Firefox case, we can simply check for Firefox // instead of having an unstable check for Gecko. this.FIREFOX = this.isBrowser && /(firefox|minefield)/i.test(navigator.userAgent); // Trident on mobile adds the android platform to the userAgent to trick detections. this.ANDROID = this.isBrowser && /android/i.test(navigator.userAgent) && !this.TRIDENT; // Safari browsers will include the Safari keyword in their userAgent. Some browsers may fake // this and just place the Safari keyword in the userAgent. To be more safe about Safari every // Safari browser should also use Webkit as its layout engine. this.SAFARI = this.isBrowser && /safari/i.test(navigator.userAgent) && this.WEBKIT; } return Platform; }()); Platform.decorators = [ { type: _angular_core.Injectable }, ]; /** * @nocollapse */ Platform.ctorParameters = function () { return []; }; /** * Cached result Set of input types support by the current browser. */ var supportedInputTypes; /** * Types of <input> that *might* be supported. */ var candidateInputTypes = [ // `color` must come first. Chrome 56 shows a warning if we change the type to `color` after // first changing it to something else: // The specified value "" does not conform to the required format. // The format is "#rrggbb" where rr, gg, bb are two-digit hexadecimal numbers. 'color', 'button', 'checkbox', 'date', 'datetime-local', 'email', 'file', 'hidden', 'image', 'month', 'number', 'password', 'radio', 'range', 'reset', 'search', 'submit', 'tel', 'text', 'time', 'url', 'week', ]; /** * @return {?} The input types supported by this browser. */ function getSupportedInputTypes() { // Result is cached. if (supportedInputTypes) { return supportedInputTypes; } // We can't check if an input type is not supported until we're on the browser, so say that // everything is supported when not on the browser. We don't use `Platform` here since it's // just a helper function and can't inject it. if (typeof document !== 'object' || !document) { supportedInputTypes = new Set(candidateInputTypes); return supportedInputTypes; } var /** @type {?} */ featureTestInput = document.createElement('input'); supportedInputTypes = new Set(candidateInputTypes.filter(function (value) { featureTestInput.setAttribute('type', value); return featureTestInput.type === value; })); return supportedInputTypes; } var PlatformModule = (function () { function PlatformModule() { } return PlatformModule; }()); PlatformModule.decorators = [ { type: _angular_core.NgModule, args: [{ providers: [Platform] },] }, ]; /** * @nocollapse */ PlatformModule.ctorParameters = function () { return []; }; /** * Time in ms to throttle the scrolling events by default. */ var DEFAULT_SCROLL_TIME = 20; /** * Service contained all registered Scrollable references and emits an event when any one of the * Scrollable references emit a scrolled event. */ var ScrollDispatcher = (function () { /** * @param {?} _ngZone * @param {?} _platform */ function ScrollDispatcher(_ngZone, _platform) { this._ngZone = _ngZone; this._platform = _platform; /** * Subject for notifying that a registered scrollable reference element has been scrolled. */ this._scrolled = new rxjs_Subject.Subject(); /** * Keeps track of the global `scroll` and `resize` subscriptions. */ this._globalSubscription = null; /** * Keeps track of the amount of subscriptions to `scrolled`. Used for cleaning up afterwards. */ this._scrolledCount = 0; /** * Map of all the scrollable references that are registered with the service and their * scroll event subscriptions. */ this.scrollableReferences = new Map(); } /** * Registers a Scrollable with the service and listens for its scrolled events. When the * scrollable is scrolled, the service emits the event in its scrolled observable. * @param {?} scrollable Scrollable instance to be registered. * @return {?} */ ScrollDispatcher.prototype.register = function (scrollable) { var _this = this; var /** @type {?} */ scrollSubscription = scrollable.elementScrolled().subscribe(function () { return _this._notify(); }); this.scrollableReferences.set(scrollable, scrollSubscription); }; /** * Deregisters a Scrollable reference and unsubscribes from its scroll event observable. * @param {?} scrollable Scrollable instance to be deregistered. * @return {?} */ ScrollDispatcher.prototype.deregister = function (scrollable) { if (this.scrollableReferences.has(scrollable)) { this.scrollableReferences.get(scrollable).unsubscribe(); this.scrollableReferences.delete(scrollable); } }; /** * Subscribes to an observable that emits an event whenever any of the registered Scrollable * references (or window, document, or body) fire a scrolled event. Can provide a time in ms * to override the default "throttle" time. * @param {?=} auditTimeInMs * @param {?=} callback * @return {?} */ ScrollDispatcher.prototype.scrolled = function (auditTimeInMs, callback) { var _this = this; if (auditTimeInMs === void 0) { auditTimeInMs = DEFAULT_SCROLL_TIME; } // Scroll events can only happen on the browser, so do nothing if we're not on the browser. if (!this._platform.isBrowser) { return rxjs_Subscription.Subscription.EMPTY; } // In the case of a 0ms delay, use an observable without auditTime // since it does add a perceptible delay in processing overhead. var /** @type {?} */ observable = auditTimeInMs > 0 ? this._scrolled.asObservable().auditTime(auditTimeInMs) : this._scrolled.asObservable(); this._scrolledCount++; if (!this._globalSubscription) { this._globalSubscription = this._ngZone.runOutsideAngular(function () { return rxjs_Observable.Observable.merge(rxjs_Observable.Observable.fromEvent(window.document, 'scroll'), rxjs_Observable.Observable.fromEvent(window, 'resize')).subscribe(function () { return _this._notify(); }); }); } // Note that we need to do the subscribing from here, in order to be able to remove // the global event listeners once there are no more subscriptions. var /** @type {?} */ subscription = observable.subscribe(callback); subscription.add(function () { _this._scrolledCount--; if (_this._globalSubscription && !_this.scrollableReferences.size && !_this._scrolledCount) { _this._globalSubscription.unsubscribe(); _this._globalSubscription = null; } }); return subscription; }; /** * Returns all registered Scrollables that contain the provided element. * @param {?} elementRef * @return {?} */ ScrollDispatcher.prototype.getScrollContainers = function (elementRef) { var _this = this; var /** @type {?} */ scrollingContainers = []; this.scrollableReferences.forEach(function (_subscription, scrollable) { if (_this.scrollableContainsElement(scrollable, elementRef)) { scrollingContainers.push(scrollable); } }); return scrollingContainers; }; /** * Returns true if the element is contained within the provided Scrollable. * @param {?} scrollable * @param {?} elementRef * @return {?} */ ScrollDispatcher.prototype.scrollableContainsElement = function (scrollable, elementRef) { var /** @type {?} */ element = elementRef.nativeElement; var /** @type {?} */ scrollableElement = scrollable.getElementRef().nativeElement; // Traverse through the element parents until we reach null, checking if any of the elements // are the scrollable's element. do { if (element == scrollableElement) { return true; } } while (element = element.parentElement); }; /** * Sends a notification that a scroll event has been fired. * @return {?} */ ScrollDispatcher.prototype._notify = function () { this._scrolled.next(); }; return ScrollDispatcher; }()); ScrollDispatcher.decorators = [ { type: _angular_core.Injectable }, ]; /** * @nocollapse */ ScrollDispatcher.ctorParameters = function () { return [ { type: _angular_core.NgZone, }, { type: Platform, }, ]; }; /** * @param {?} parentDispatcher * @param {?} ngZone * @param {?} platform * @return {?} */ function SCROLL_DISPATCHER_PROVIDER_FACTORY(parentDispatcher, ngZone, platform) { return parentDispatcher || new ScrollDispatcher(ngZone, platform); } var SCROLL_DISPATCHER_PROVIDER = { // If there is already a ScrollDispatcher available, use that. Otherwise, provide a new one. provide: ScrollDispatcher, deps: [[new _angular_core.Optional(), new _angular_core.SkipSelf(), ScrollDispatcher], _angular_core.NgZone, Platform], useFactory: SCROLL_DISPATCHER_PROVIDER_FACTORY }; /** * Simple utility for getting the bounds of the browser viewport. * \@docs-private */ var ViewportRuler = (function () { /** * @param {?} scrollDispatcher */ function ViewportRuler(scrollDispatcher) { var _this = this; // Subscribe to scroll and resize events and update the document rectangle on changes. scrollDispatcher.scrolled(null, function () { return _this._cacheViewportGeometry(); }); } /** * Gets a ClientRect for the viewport's bounds. * @param {?=} documentRect * @return {?} */ ViewportRuler.prototype.getViewportRect = function (documentRect) { if (documentRect === void 0) { documentRect = this._documentRect; } // Cache the document bounding rect so that we don't recompute it for multiple calls. if (!documentRect) { this._cacheViewportGeometry(); documentRect = this._documentRect; } // Use the document element's bounding rect rather than the window scroll properties // (e.g. pageYOffset, scrollY) due to in issue in Chrome and IE where window scroll // properties and client coordinates (boundingClientRect, clientX/Y, etc.) are in different // conceptual viewports. Under most circumstances these viewports are equivalent, but they // can disagree when the page is pinch-zoomed (on devices that support touch). // See https://bugs.chromium.org/p/chromium/issues/detail?id=489206#c4 // We use the documentElement instead of the body because, by default (without a css reset) // browsers typically give the document body an 8px margin, which is not included in // getBoundingClientRect(). var /** @type {?} */ scrollPosition = this.getViewportScrollPosition(documentRect); var /** @type {?} */ height = window.innerHeight; var /** @type {?} */ width = window.innerWidth; return { top: scrollPosition.top, left: scrollPosition.left, bottom: scrollPosition.top + height, right: scrollPosition.left + width, height: height, width: width, }; }; /** * Gets the (top, left) scroll position of the viewport. * @param {?=} documentRect * @return {?} */ ViewportRuler.prototype.getViewportScrollPosition = function (documentRect) { if (documentRect === void 0) { documentRect = this._documentRect; } // Cache the document bounding rect so that we don't recompute it for multiple calls. if (!documentRect) { this._cacheViewportGeometry(); documentRect = this._documentRect; } // The top-left-corner of the viewport is determined by the scroll position of the document // body, normally just (scrollLeft, scrollTop). However, Chrome and Firefox disagree about // whether `document.body` or `document.documentElement` is the scrolled element, so reading // `scrollTop` and `scrollLeft` is inconsistent. However, using the bounding rect of // `document.documentElement` works consistently, where the `top` and `left` values will // equal negative the scroll position. var /** @type {?} */ top = -documentRect.top || document.body.scrollTop || window.scrollY || document.documentElement.scrollTop || 0; var /** @type {?} */ left = -documentRect.left || document.body.scrollLeft || window.scrollX || document.documentElement.scrollLeft || 0; return { top: top, left: left }; }; /** * Caches the latest client rectangle of the document element. * @return {?} */ ViewportRuler.prototype._cacheViewportGeometry = function () { this._documentRect = document.documentElement.getBoundingClientRect(); }; return ViewportRuler; }()); ViewportRuler.decorators = [ { type: _angular_core.Injectable }, ]; /** * @nocollapse */ ViewportRuler.ctorParameters = function () { return [ { type: ScrollDispatcher, }, ]; }; /** * @param {?} parentRuler * @param {?} scrollDispatcher * @return {?} */ function VIEWPORT_RULER_PROVIDER_FACTORY(parentRuler, scrollDispatcher) { return parentRuler || new ViewportRuler(scrollDispatcher); } var VIEWPORT_RULER_PROVIDER = { // If there is already a ViewportRuler available, use that. Otherwise, provide a new one. provide: ViewportRuler, deps: [[new _angular_core.Optional(), new _angular_core.SkipSelf(), ViewportRuler], ScrollDispatcher], useFactory: VIEWPORT_RULER_PROVIDER_FACTORY }; /** * Injection token that can be used to specify the global ripple options. */ var MD_RIPPLE_GLOBAL_OPTIONS = new _angular_core.InjectionToken('md-ripple-global-options'); var MdRipple = (function () { /** * @param {?} elementRef * @param {?} ngZone * @param {?} ruler * @param {?} platform * @param {?} globalOptions */ function MdRipple(elementRef, ngZone, ruler, platform, globalOptions) { /** * If set, the radius in pixels of foreground ripples when fully expanded. If unset, the radius * will be the distance from the center of the ripple to the furthest corner of the host element's * bounding rectangle. */ this.radius = 0; /** * If set, the normal duration of ripple animations is divided by this value. For example, * setting it to 0.5 will cause the animations to take twice as long. * A changed speedFactor will not modify the fade-out duration of the ripples. */ this.speedFactor = 1; this._rippleRenderer = new RippleRenderer(elementRef, ngZone, ruler, platform); this._globalOptions = globalOptions ? globalOptions : {}; this._updateRippleRenderer(); } /** * @param {?} changes * @return {?} */ MdRipple.prototype.ngOnChanges = function (changes) { if (changes['trigger'] && this.trigger) { this._rippleRenderer.setTriggerElement(this.trigger); } this._updateRippleRenderer(); }; /** * @return {?} */ MdRipple.prototype.ngOnDestroy = function () { // Set the trigger element to null to cleanup all listeners. this._rippleRenderer.setTriggerElement(null); }; /** * Launches a manual ripple at the specified position. * @param {?} pageX * @param {?} pageY * @param {?=} config * @return {?} */ MdRipple.prototype.launch = function (pageX, pageY, config) { if (config === void 0) { config = this.rippleConfig; } return this._rippleRenderer.fadeInRipple(pageX, pageY, config); }; /** * Fades out all currently showing ripple elements. * @return {?} */ MdRipple.prototype.fadeOutAll = function () { this._rippleRenderer.fadeOutAll(); }; Object.defineProperty(MdRipple.prototype, "rippleConfig", { /** * Ripple configuration from the directive's input values. * @return {?} */ get: function () { return { centered: this.centered, speedFactor: this.speedFactor * (this._globalOptions.baseSpeedFactor |