UNPKG

md2

Version:

Angular2 based Material Design components, directives and services are Accordion, Autocomplete, Chips(Tags), Collapse, Colorpicker, Data Table, Datepicker, Dialog(Modal), Menu, Multiselect, Select, Tabs, Tags(Chips), Toast and Tooltip.

1,182 lines (1,167 loc) 581 kB
/** * @license Md2 v0.0.33 * Copyright (c) 2017 Promact, Inc. http://code.promactinfo.com/md2/ * License: MIT */ import { ApplicationRef, Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactoryResolver, ContentChildren, Directive, ElementRef, EventEmitter, HostBinding, HostListener, Inject, Injectable, InjectionToken, Injector, Input, IterableDiffers, NgModule, NgZone, Optional, Output, Pipe, QueryList, Renderer, Renderer2, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation, forwardRef, isDevMode } from '@angular/core'; import { DOCUMENT, HammerGestureConfig } from '@angular/platform-browser'; import { Subject } from 'rxjs/Subject'; import 'rxjs/add/operator/debounceTime'; import { CommonModule } from '@angular/common'; import { Observable } from 'rxjs/Observable'; import { Subscription } from 'rxjs/Subscription'; import 'rxjs/add/observable/fromEvent'; import 'rxjs/add/observable/merge'; import 'rxjs/add/operator/auditTime'; import 'rxjs/add/operator/first'; import 'rxjs/add/observable/of'; import { animate, keyframes, state, style, transition, trigger } from '@angular/animations'; import { FormsModule, NG_VALIDATORS, NG_VALUE_ACCESSOR, NgControl, NgForm, Validators } from '@angular/forms'; import 'rxjs/add/operator/startWith'; import 'rxjs/add/operator/filter'; var __decorate$3 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata$1 = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param$1 = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; const MATERIAL_COMPATIBILITY_MODE = new InjectionToken('md-compatibility-mode'); /** * Returns an exception to be thrown if the consumer has used * an invalid Material prefix on a component. * @docs-private */ 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. */ const MAT_ELEMENTS_SELECTOR = ` [mat-button], [mat-fab], [mat-icon-button], [mat-mini-fab], [mat-raised-button], [matCardSubtitle], [matCardTitle], [matDialogActions], [matDialogClose], [matDialogContent], [matDialogTitle], [matLine], [matTabLabel], [matTabLink], [matTabNav], [matTooltip], mat-autocomplete, mat-button-toggle, mat-button-toggle, mat-button-toggle-group, mat-card, mat-card-actions, mat-card-content, mat-card-footer, mat-card-header, mat-card-subtitle, mat-card-title, mat-card-title-group, mat-checkbox, mat-chip, mat-dialog-actions, mat-dialog-container, mat-dialog-content, mat-divider, mat-error, mat-grid-list, mat-grid-tile, mat-grid-tile-footer, mat-grid-tile-header, mat-hint, mat-icon, mat-list, mat-list-item, mat-menu, mat-nav-list, mat-option, mat-placeholder, mat-progress-bar, mat-pseudo-checkbox, mat-radio-button, mat-radio-group, mat-select, mat-sidenav, mat-sidenav-container, mat-slider, mat-spinner, mat-tab, mat-tab-group, mat-toolbar`; /** Selector that matches all elements that may have style collisions with AngularJS Material. */ const MD_ELEMENTS_SELECTOR = ` [md-button], [md-fab], [md-icon-button], [md-mini-fab], [md-raised-button], [mdCardSubtitle], [mdCardTitle], [mdDialogActions], [mdDialogClose], [mdDialogContent], [mdDialogTitle], [mdLine], [mdTabLabel], [mdTabLink], [mdTabNav], [mdTooltip], md-autocomplete, md-button-toggle, md-button-toggle, md-button-toggle-group, md-card, md-card-actions, md-card-content, md-card-footer, md-card-header, md-card-subtitle, md-card-title, md-card-title-group, md-checkbox, md-chip, md-dialog-actions, md-dialog-container, md-dialog-content, md-divider, md-error, md-grid-list, md-grid-tile, md-grid-tile-footer, md-grid-tile-header, md-hint, md-icon, md-list, md-list-item, md-menu, md-nav-list, md-option, md-placeholder, md-progress-bar, md-pseudo-checkbox, md-radio-button, md-radio-group, md-select, md-sidenav, md-sidenav-container, md-slider, md-spinner, md-tab, md-tab-group, md-toolbar`; /** Directive that enforces that the `mat-` prefix cannot be used. */ let MatPrefixRejector = class MatPrefixRejector { constructor(isCompatibilityMode, elementRef) { if (!isCompatibilityMode) { throw getMdCompatibilityInvalidPrefixError('mat', elementRef.nativeElement.nodeName); } } }; MatPrefixRejector = __decorate$3([ Directive({ selector: MAT_ELEMENTS_SELECTOR }), __param$1(0, Optional()), __param$1(0, Inject(MATERIAL_COMPATIBILITY_MODE)), __metadata$1("design:paramtypes", [Boolean, ElementRef]) ], MatPrefixRejector); /** Directive that enforces that the `md-` prefix cannot be used. */ let MdPrefixRejector = class MdPrefixRejector { constructor(isCompatibilityMode, elementRef) { if (isCompatibilityMode) { throw getMdCompatibilityInvalidPrefixError('md', elementRef.nativeElement.nodeName); } } }; MdPrefixRejector = __decorate$3([ Directive({ selector: MD_ELEMENTS_SELECTOR }), __param$1(0, Optional()), __param$1(0, Inject(MATERIAL_COMPATIBILITY_MODE)), __metadata$1("design:paramtypes", [Boolean, ElementRef]) ], MdPrefixRejector); /** * 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. */ let CompatibilityModule = class CompatibilityModule { }; CompatibilityModule = __decorate$3([ NgModule({ declarations: [MatPrefixRejector, MdPrefixRejector], exports: [MatPrefixRejector, MdPrefixRejector], }) ], CompatibilityModule); /** * 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. */ let NoConflictStyleCompatibilityMode = class NoConflictStyleCompatibilityMode { }; NoConflictStyleCompatibilityMode = __decorate$3([ NgModule({ providers: [{ provide: MATERIAL_COMPATIBILITY_MODE, useValue: true, }], }) ], NoConflictStyleCompatibilityMode); var __decorate$2 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; /** Injection token that configures whether the Material sanity checks are enabled. */ const MATERIAL_SANITY_CHECKS = new 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). */ let MdCommonModule = class MdCommonModule { constructor(_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 && isDevMode()) { this._checkDoctype(); this._checkTheme(); this._hasDoneGlobalChecks = true; } } _checkDoctype() { 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.'); } } _checkTheme() { if (typeof getComputedStyle === 'function') { const 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); } } }; MdCommonModule = __decorate$2([ NgModule({ imports: [CompatibilityModule], exports: [CompatibilityModule], providers: [{ provide: MATERIAL_SANITY_CHECKS, useValue: true, }], }), __param(0, Optional()), __param(0, Inject(DOCUMENT)), __param(1, Optional()), __param(1, Inject(MATERIAL_SANITY_CHECKS)), __metadata("design:paramtypes", [Object, Boolean]) ], MdCommonModule); var __decorate$1 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; /** * 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. */ let MdLine = class MdLine { }; MdLine = __decorate$1([ Directive({ selector: '[md-line], [mat-line], [mdLine], [matLine]', host: { 'class': 'mat-line' } }) ], MdLine); /** * Helper that takes a query list of lines and sets the correct class on the host. * @docs-private */ class MdLineSetter { constructor(_lines, _renderer, _element) { this._lines = _lines; this._renderer = _renderer; this._element = _element; this._setLineClass(this._lines.length); this._lines.changes.subscribe(() => { this._setLineClass(this._lines.length); }); } _setLineClass(count) { this._resetClasses(); if (count === 2 || count === 3) { this._setClass(`mat-${count}-line`, true); } else if (count > 3) { this._setClass(`mat-multi-line`, true); } } _resetClasses() { this._setClass('mat-2-line', false); this._setClass('mat-3-line', false); this._setClass('mat-multi-line', false); } _setClass(className, isAdd) { if (isAdd) { this._renderer.addClass(this._element.nativeElement, className); } else { this._renderer.removeClass(this._element.nativeElement, className); } } } let MdLineModule = class MdLineModule { }; MdLineModule = __decorate$1([ NgModule({ imports: [MdCommonModule], exports: [MdLine, MdCommonModule], declarations: [MdLine], }) ], MdLineModule); var __decorate$4 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata$2 = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; /** * 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. */ let Dir = class Dir { /** * 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. */ constructor() { /** Layout direction of the element. */ this._dir = 'ltr'; /** Event emitted when the direction changes. */ this.dirChange = new EventEmitter(); } /** @docs-private */ get dir() { return this._dir; } set dir(v) { let old = this._dir; this._dir = v; if (old != this._dir) { this.dirChange.emit(); } } /** Current layout direction of the element. */ get value() { return this.dir; } set value(v) { this.dir = v; } }; __decorate$4([ Input('dir'), __metadata$2("design:type", String) ], Dir.prototype, "_dir", void 0); __decorate$4([ Output(), __metadata$2("design:type", Object) ], Dir.prototype, "dirChange", void 0); __decorate$4([ HostBinding('attr.dir'), __metadata$2("design:type", String), __metadata$2("design:paramtypes", [String]) ], Dir.prototype, "dir", null); Dir = __decorate$4([ Directive({ selector: '[dir]', // TODO(hansl): maybe `$implicit` isn't the best option here, but for now that's the best we got. exportAs: '$implicit' }) ], Dir); let RtlModule = class RtlModule { }; RtlModule = __decorate$4([ NgModule({ exports: [Dir], declarations: [Dir] }) ], RtlModule); var __decorate$5 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata$3 = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; /** * Factory that creates a new MutationObserver and allows us to stub it out in unit tests. * @docs-private */ let MdMutationObserverFactory = class MdMutationObserverFactory { create(callback) { return typeof MutationObserver === 'undefined' ? null : new MutationObserver(callback); } }; MdMutationObserverFactory = __decorate$5([ Injectable() ], MdMutationObserverFactory); /** * Directive that triggers a callback whenever the content of * its associated element has changed. */ let ObserveContent = class ObserveContent { constructor(_mutationObserverFactory, _elementRef) { this._mutationObserverFactory = _mutationObserverFactory; this._elementRef = _elementRef; /** Event emitted for each change in the element's content. */ this.event = new EventEmitter(); /** Used for debouncing the emitted values to the observeContent event. */ this._debouncer = new Subject(); } ngAfterContentInit() { if (this.debounce > 0) { this._debouncer .debounceTime(this.debounce) .subscribe(mutations => this.event.emit(mutations)); } else { this._debouncer.subscribe(mutations => this.event.emit(mutations)); } this._observer = this._mutationObserverFactory.create((mutations) => { this._debouncer.next(mutations); }); if (this._observer) { this._observer.observe(this._elementRef.nativeElement, { characterData: true, childList: true, subtree: true }); } } ngOnDestroy() { if (this._observer) { this._observer.disconnect(); this._debouncer.complete(); this._debouncer = this._observer = null; } } }; __decorate$5([ Output('cdkObserveContent'), __metadata$3("design:type", Object) ], ObserveContent.prototype, "event", void 0); __decorate$5([ Input(), __metadata$3("design:type", Number) ], ObserveContent.prototype, "debounce", void 0); ObserveContent = __decorate$5([ Directive({ selector: '[cdkObserveContent]' }), __metadata$3("design:paramtypes", [MdMutationObserverFactory, ElementRef]) ], ObserveContent); let ObserveContentModule = class ObserveContentModule { }; ObserveContentModule = __decorate$5([ NgModule({ exports: [ObserveContent], declarations: [ObserveContent], providers: [MdMutationObserverFactory] }) ], ObserveContentModule); /** Possible states for a ripple element. */ var RippleState; (function (RippleState) { RippleState[RippleState["FADING_IN"] = 0] = "FADING_IN"; RippleState[RippleState["VISIBLE"] = 1] = "VISIBLE"; RippleState[RippleState["FADING_OUT"] = 2] = "FADING_OUT"; RippleState[RippleState["HIDDEN"] = 3] = "HIDDEN"; })(RippleState || (RippleState = {})); /** * Reference to a previously launched ripple element. */ class RippleRef { constructor(_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. */ fadeOut() { this._renderer.fadeOutRipple(this); } } /** Fade-in duration for the ripples. Can be modified with the speedFactor option. */ const RIPPLE_FADE_IN_DURATION = 450; /** Fade-out duration for the ripples in milliseconds. This can't be modified by the speedFactor. */ const 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 */ class RippleRenderer { constructor(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. */ fadeInRipple(pageX, pageY, config = {}) { let 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. let scrollPosition = this._ruler.getViewportScrollPosition(); pageX -= scrollPosition.left; pageY -= scrollPosition.top; } let radius = config.radius || distanceToFurthestCorner(pageX, pageY, containerRect); let duration = RIPPLE_FADE_IN_DURATION * (1 / (config.speedFactor || 1)); let offsetX = pageX - containerRect.left; let offsetY = pageY - containerRect.top; let 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. let 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(() => { rippleRef.state = RippleState.VISIBLE; if (!config.persistent && !this._isMousedown) { rippleRef.fadeOut(); } }, duration); return rippleRef; } /** Fades out a ripple reference. */ fadeOutRipple(rippleRef) { // For ripples that are not active anymore, don't re-un the fade-out animation. if (!this._activeRipples.delete(rippleRef)) { return; } let 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(() => { rippleRef.state = RippleState.HIDDEN; rippleEl.parentNode.removeChild(rippleEl); }, RIPPLE_FADE_OUT_DURATION); } /** Fades out all currently active ripples. */ fadeOutAll() { this._activeRipples.forEach(ripple => ripple.fadeOut()); } /** Sets the trigger element and registers the mouse events. */ setTriggerElement(element) { // Remove all previously register event listeners from the trigger element. if (this._triggerElement) { this._triggerEvents.forEach((fn, type) => this._triggerElement.removeEventListener(type, fn)); } if (element) { // If the element is not null, register all event listeners on the trigger element. this._ngZone.runOutsideAngular(() => { this._triggerEvents.forEach((fn, type) => element.addEventListener(type, fn)); }); } this._triggerElement = element; } /** Listener being called on mousedown event. */ onMousedown(event) { if (!this.rippleDisabled) { this._isMousedown = true; this.fadeInRipple(event.pageX, event.pageY, this.rippleConfig); } } /** Listener being called on mouseup event. */ onMouseup() { this._isMousedown = false; // Fade-out all ripples that are completely visible and not persistent. this._activeRipples.forEach(ripple => { if (!ripple.config.persistent && ripple.state === RippleState.VISIBLE) { ripple.fadeOut(); } }); } /** Listener being called on mouseleave event. */ onMouseLeave() { if (this._isMousedown) { this.onMouseup(); } } /** Runs a timeout outside of the Angular zone to avoid triggering the change detection. */ runTimeoutOutsideZone(fn, delay = 0) { this._ngZone.runOutsideAngular(() => setTimeout(fn, delay)); } } /** Enforces a style recalculation of a DOM element by computing its styles. */ // TODO(devversion): Move into global utility function. 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. */ function distanceToFurthestCorner(x, y, rect) { const distX = Math.max(Math.abs(x - rect.left), Math.abs(x - rect.right)); const distY = Math.max(Math.abs(y - rect.top), Math.abs(y - rect.bottom)); return Math.sqrt(distX * distX + distY * distY); } var __decorate$12 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; // Whether the current platform supports the V8 Break Iterator. The V8 check // is necessary to detect all Blink based browsers. const 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 */ let Platform = class Platform { /** * Service to detect the current platform by comparing the userAgent strings and * checking browser-specific global properties. * @docs-private */ constructor() { 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; } }; Platform = __decorate$12([ Injectable() ], Platform); /** Cached result Set of input types support by the current browser. */ let supportedInputTypes; /** Types of <input> that *might* be supported. */ const 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', ]; /** @returns 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; } let featureTestInput = document.createElement('input'); supportedInputTypes = new Set(candidateInputTypes.filter(value => { featureTestInput.setAttribute('type', value); return featureTestInput.type === value; })); return supportedInputTypes; } var __decorate$11 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; let PlatformModule = class PlatformModule { }; PlatformModule = __decorate$11([ NgModule({ providers: [Platform] }) ], PlatformModule); var __decorate$10 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata$6 = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; /** Time in ms to throttle the scrolling events by default. */ const 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. */ let ScrollDispatcher = class ScrollDispatcher { constructor(_ngZone, _platform) { this._ngZone = _ngZone; this._platform = _platform; /** Subject for notifying that a registered scrollable reference element has been scrolled. */ this._scrolled = new 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. */ register(scrollable) { const scrollSubscription = scrollable.elementScrolled().subscribe(() => 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. */ deregister(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. */ scrolled(auditTimeInMs = DEFAULT_SCROLL_TIME, callback) { // Scroll events can only happen on the browser, so do nothing if we're not on the browser. if (!this._platform.isBrowser) { return Subscription.EMPTY; } // In the case of a 0ms delay, use an observable without auditTime // since it does add a perceptible delay in processing overhead. let observable = auditTimeInMs > 0 ? this._scrolled.asObservable().auditTime(auditTimeInMs) : this._scrolled.asObservable(); this._scrolledCount++; if (!this._globalSubscription) { this._globalSubscription = this._ngZone.runOutsideAngular(() => { return Observable.merge(Observable.fromEvent(window.document, 'scroll'), Observable.fromEvent(window, 'resize')).subscribe(() => 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. let subscription = observable.subscribe(callback); subscription.add(() => { 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. */ getScrollContainers(elementRef) { const scrollingContainers = []; this.scrollableReferences.forEach((_subscription, scrollable) => { if (this.scrollableContainsElement(scrollable, elementRef)) { scrollingContainers.push(scrollable); } }); return scrollingContainers; } /** Returns true if the element is contained within the provided Scrollable. */ scrollableContainsElement(scrollable, elementRef) { let element = elementRef.nativeElement; let 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. */ _notify() { this._scrolled.next(); } }; ScrollDispatcher = __decorate$10([ Injectable(), __metadata$6("design:paramtypes", [NgZone, Platform]) ], ScrollDispatcher); function SCROLL_DISPATCHER_PROVIDER_FACTORY(parentDispatcher, ngZone, platform) { return parentDispatcher || new ScrollDispatcher(ngZone, platform); } const SCROLL_DISPATCHER_PROVIDER = { // If there is already a ScrollDispatcher available, use that. Otherwise, provide a new one. provide: ScrollDispatcher, deps: [[new Optional(), new SkipSelf(), ScrollDispatcher], NgZone, Platform], useFactory: SCROLL_DISPATCHER_PROVIDER_FACTORY }; var __decorate$9 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata$5 = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; /** * Simple utility for getting the bounds of the browser viewport. * @docs-private */ let ViewportRuler = class ViewportRuler { constructor(scrollDispatcher) { // Subscribe to scroll and resize events and update the document rectangle on changes. scrollDispatcher.scrolled(null, () => this._cacheViewportGeometry()); } /** Gets a ClientRect for the viewport's bounds. */ getViewportRect(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(). const scrollPosition = this.getViewportScrollPosition(documentRect); const height = window.innerHeight; const width = window.innerWidth; return { top: scrollPosition.top, left: scrollPosition.left, bottom: scrollPosition.top + height, right: scrollPosition.left + width, height, width, }; } /** * Gets the (top, left) scroll position of the viewport. * @param documentRect */ getViewportScrollPosition(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. const top = -documentRect.top || document.body.scrollTop || window.scrollY || document.documentElement.scrollTop || 0; const left = -documentRect.left || document.body.scrollLeft || window.scrollX || document.documentElement.scrollLeft || 0; return { top, left }; } /** Caches the latest client rectangle of the document element. */ _cacheViewportGeometry() { this._documentRect = document.documentElement.getBoundingClientRect(); } }; ViewportRuler = __decorate$9([ Injectable(), __metadata$5("design:paramtypes", [ScrollDispatcher]) ], ViewportRuler); function VIEWPORT_RULER_PROVIDER_FACTORY(parentRuler, scrollDispatcher) { return parentRuler || new ViewportRuler(scrollDispatcher); } const VIEWPORT_RULER_PROVIDER = { // If there is already a ViewportRuler available, use that. Otherwise, provide a new one. provide: ViewportRuler, deps: [[new Optional(), new SkipSelf(), ViewportRuler], ScrollDispatcher], useFactory: VIEWPORT_RULER_PROVIDER_FACTORY }; var __decorate$8 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata$4 = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param$2 = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; /** Injection token that can be used to specify the global ripple options. */ const MD_RIPPLE_GLOBAL_OPTIONS = new InjectionToken('md-ripple-global-options'); let MdRipple = class MdRipple { constructor(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(); } ngOnChanges(changes) { if (changes['trigger'] && this.trigger) { this._rippleRenderer.setTriggerElement(this.trigger); } this._updateRippleRenderer(); } ngOnDestroy() { // Set the trigger element to null to cleanup all listeners. this._rippleRenderer.setTriggerElement(null); } /** Launches a manual ripple at the specified position. */ launch(pageX, pageY, config = this.rippleConfig) { return this._rippleRenderer.fadeInRipple(pageX, pageY, config); } /** Fades out all currently showing ripple elements. */ fadeOutAll() { this._rippleRenderer.fadeOutAll(); } /** Ripple configuration from the directive's input values. */ get rippleConfig() { return { centered: this.centered, speedFactor: this.speedFactor * (this._globalOptions.baseSpeedFactor || 1), radius: this.radius, color: this.color }; } /** Updates the ripple renderer with the latest ripple configuration. */ _updateRippleRenderer() { this._rippleRenderer.rippleDisabled = this._globalOptions.disabled || this.disabled; this._rippleRenderer.rippleConfig = this.rippleConfig; } }; __decorate$8([ Input('mdRippleTrigger'), __metadata$4("design:type", HTMLElement) ], MdRipple.prototype, "trigger", void 0); __decorate$8([ Input('mdRippleCentered'), __metadata$4("design:type", Boolean) ], MdRipple.prototype, "centered", void 0); __decorate$8([ Input('mdRippleDisabled'), __metadata$4("design:type", Boolean) ], MdRipple.prototype, "disabled", void 0); __decorate$8([ Input('mdRippleRadius'), __metadata$4("design:type", Number) ], MdRipple.prototype, "radius", void 0); __decorate$8([ Input('mdRippleSpeedFactor'), __metadata$4("design:type", Number) ], MdRipple.prototype, "speedFactor", void 0); __decorate$8([ Input('mdRippleColor'), __metadata$4("design:type", String) ], MdRipple.prototype, "color", void 0); __decorate$8([ Input('mdRippleUnbounded'), __metadata$4("design:type", Boolean) ], MdRipple.prototype, "unbounded", void 0); MdRipple = __decorate$8([ Directive({ selector: '[md-ripple], [mat-ripple], [mdRipple], [matRipple]', exportAs: 'mdRipple', host: { 'class': 'mat-ripple', '[class.mat-ripple-unbounded]': 'unbounded' } }), __param$2(4, Optional()), __param$2(4, Inject(MD_RIPPLE_GLOBAL_OPTIONS)), __metadata$4("design:paramtypes", [ElementRef, NgZone, ViewportRuler, Platform, Object]) ], MdRipple); var __decorate$14 = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata$7 = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; /** * Sends an event when the directive's element is scrolled. Registers itself with the * ScrollDispatcher service to include itself as part of its collection of scrolling events that it * can be listened to through the service. */ let Scrollable = class Scrollable { constructor(_elementRef, _scroll, _ngZone, _renderer) { this._elementRef = _elementRef; this._scroll = _scroll; this._ngZone = _ngZone; this._renderer = _renderer; this._elementScrolled = new Subject(); } ngOnInit() { this._scrollListener = this._ngZone.runOutsideAngular(() => { return this._renderer.listen(this.getElementRef().nativeElement, 'scroll', (event) => { this._elementScrolled.next(event); }); }); this._scroll.register(this); } ngOnDestroy() { this._scroll.deregister(this); if (this._scrollListener) { this._scrollListener(); this._scrollListener = null; } } /** * Returns observable that emits when a scroll event is fired on the host element. */ elementScrolled() { return this._elementScrolled.asObservable(); } getElementRef() { return this._elementRef; } }; Scrollable = __decorate$14([ Directive({