| /** |
| * @license |
| * Copyright Google LLC 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 |
| */ |
| import { coerceBooleanProperty, coerceNumberProperty, coerceElement } from '@angular/cdk/coercion'; |
| import { Directive, ElementRef, EventEmitter, Injectable, Input, NgModule, NgZone, Output, ɵɵdefineInjectable, ɵɵinject } from '@angular/core'; |
| import { Observable, Subject } from 'rxjs'; |
| import { debounceTime } from 'rxjs/operators'; |
| |
| /** |
| * @fileoverview added by tsickle |
| * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc |
| */ |
| /** |
| * Factory that creates a new MutationObserver and allows us to stub it out in unit tests. |
| * \@docs-private |
| */ |
| class MutationObserverFactory { |
| /** |
| * @param {?} callback |
| * @return {?} |
| */ |
| create(callback) { |
| return typeof MutationObserver === 'undefined' ? null : new MutationObserver(callback); |
| } |
| } |
| MutationObserverFactory.decorators = [ |
| { type: Injectable, args: [{ providedIn: 'root' },] }, |
| ]; |
| /** @nocollapse */ MutationObserverFactory.ngInjectableDef = ɵɵdefineInjectable({ factory: function MutationObserverFactory_Factory() { return new MutationObserverFactory(); }, token: MutationObserverFactory, providedIn: "root" }); |
| /** |
| * An injectable service that allows watching elements for changes to their content. |
| */ |
| class ContentObserver { |
| /** |
| * @param {?} _mutationObserverFactory |
| */ |
| constructor(_mutationObserverFactory) { |
| this._mutationObserverFactory = _mutationObserverFactory; |
| /** |
| * Keeps track of the existing MutationObservers so they can be reused. |
| */ |
| this._observedElements = new Map(); |
| } |
| /** |
| * @return {?} |
| */ |
| ngOnDestroy() { |
| this._observedElements.forEach((/** |
| * @param {?} _ |
| * @param {?} element |
| * @return {?} |
| */ |
| (_, element) => this._cleanupObserver(element))); |
| } |
| /** |
| * @param {?} elementOrRef |
| * @return {?} |
| */ |
| observe(elementOrRef) { |
| /** @type {?} */ |
| const element = coerceElement(elementOrRef); |
| return new Observable((/** |
| * @param {?} observer |
| * @return {?} |
| */ |
| (observer) => { |
| /** @type {?} */ |
| const stream = this._observeElement(element); |
| /** @type {?} */ |
| const subscription = stream.subscribe(observer); |
| return (/** |
| * @return {?} |
| */ |
| () => { |
| subscription.unsubscribe(); |
| this._unobserveElement(element); |
| }); |
| })); |
| } |
| /** |
| * Observes the given element by using the existing MutationObserver if available, or creating a |
| * new one if not. |
| * @private |
| * @param {?} element |
| * @return {?} |
| */ |
| _observeElement(element) { |
| if (!this._observedElements.has(element)) { |
| /** @type {?} */ |
| const stream = new Subject(); |
| /** @type {?} */ |
| const observer = this._mutationObserverFactory.create((/** |
| * @param {?} mutations |
| * @return {?} |
| */ |
| mutations => stream.next(mutations))); |
| if (observer) { |
| observer.observe(element, { |
| characterData: true, |
| childList: true, |
| subtree: true |
| }); |
| } |
| this._observedElements.set(element, { observer, stream, count: 1 }); |
| } |
| else { |
| (/** @type {?} */ (this._observedElements.get(element))).count++; |
| } |
| return (/** @type {?} */ (this._observedElements.get(element))).stream; |
| } |
| /** |
| * Un-observes the given element and cleans up the underlying MutationObserver if nobody else is |
| * observing this element. |
| * @private |
| * @param {?} element |
| * @return {?} |
| */ |
| _unobserveElement(element) { |
| if (this._observedElements.has(element)) { |
| (/** @type {?} */ (this._observedElements.get(element))).count--; |
| if (!(/** @type {?} */ (this._observedElements.get(element))).count) { |
| this._cleanupObserver(element); |
| } |
| } |
| } |
| /** |
| * Clean up the underlying MutationObserver for the specified element. |
| * @private |
| * @param {?} element |
| * @return {?} |
| */ |
| _cleanupObserver(element) { |
| if (this._observedElements.has(element)) { |
| const { observer, stream } = (/** @type {?} */ (this._observedElements.get(element))); |
| if (observer) { |
| observer.disconnect(); |
| } |
| stream.complete(); |
| this._observedElements.delete(element); |
| } |
| } |
| } |
| ContentObserver.decorators = [ |
| { type: Injectable, args: [{ providedIn: 'root' },] }, |
| ]; |
| /** @nocollapse */ |
| ContentObserver.ctorParameters = () => [ |
| { type: MutationObserverFactory } |
| ]; |
| /** @nocollapse */ ContentObserver.ngInjectableDef = ɵɵdefineInjectable({ factory: function ContentObserver_Factory() { return new ContentObserver(ɵɵinject(MutationObserverFactory)); }, token: ContentObserver, providedIn: "root" }); |
| /** |
| * Directive that triggers a callback whenever the content of |
| * its associated element has changed. |
| */ |
| class CdkObserveContent { |
| /** |
| * @param {?} _contentObserver |
| * @param {?} _elementRef |
| * @param {?} _ngZone |
| */ |
| constructor(_contentObserver, _elementRef, _ngZone) { |
| this._contentObserver = _contentObserver; |
| this._elementRef = _elementRef; |
| this._ngZone = _ngZone; |
| /** |
| * Event emitted for each change in the element's content. |
| */ |
| this.event = new EventEmitter(); |
| this._disabled = false; |
| this._currentSubscription = null; |
| } |
| /** |
| * Whether observing content is disabled. This option can be used |
| * to disconnect the underlying MutationObserver until it is needed. |
| * @return {?} |
| */ |
| get disabled() { return this._disabled; } |
| /** |
| * @param {?} value |
| * @return {?} |
| */ |
| set disabled(value) { |
| this._disabled = coerceBooleanProperty(value); |
| this._disabled ? this._unsubscribe() : this._subscribe(); |
| } |
| /** |
| * Debounce interval for emitting the changes. |
| * @return {?} |
| */ |
| get debounce() { return this._debounce; } |
| /** |
| * @param {?} value |
| * @return {?} |
| */ |
| set debounce(value) { |
| this._debounce = coerceNumberProperty(value); |
| this._subscribe(); |
| } |
| /** |
| * @return {?} |
| */ |
| ngAfterContentInit() { |
| if (!this._currentSubscription && !this.disabled) { |
| this._subscribe(); |
| } |
| } |
| /** |
| * @return {?} |
| */ |
| ngOnDestroy() { |
| this._unsubscribe(); |
| } |
| /** |
| * @private |
| * @return {?} |
| */ |
| _subscribe() { |
| this._unsubscribe(); |
| /** @type {?} */ |
| const stream = this._contentObserver.observe(this._elementRef); |
| // TODO(mmalerba): We shouldn't be emitting on this @Output() outside the zone. |
| // Consider brining it back inside the zone next time we're making breaking changes. |
| // Bringing it back inside can cause things like infinite change detection loops and changed |
| // after checked errors if people's code isn't handling it properly. |
| this._ngZone.runOutsideAngular((/** |
| * @return {?} |
| */ |
| () => { |
| this._currentSubscription = |
| (this.debounce ? stream.pipe(debounceTime(this.debounce)) : stream).subscribe(this.event); |
| })); |
| } |
| /** |
| * @private |
| * @return {?} |
| */ |
| _unsubscribe() { |
| if (this._currentSubscription) { |
| this._currentSubscription.unsubscribe(); |
| } |
| } |
| } |
| CdkObserveContent.decorators = [ |
| { type: Directive, args: [{ |
| selector: '[cdkObserveContent]', |
| exportAs: 'cdkObserveContent', |
| },] }, |
| ]; |
| /** @nocollapse */ |
| CdkObserveContent.ctorParameters = () => [ |
| { type: ContentObserver }, |
| { type: ElementRef }, |
| { type: NgZone } |
| ]; |
| CdkObserveContent.propDecorators = { |
| event: [{ type: Output, args: ['cdkObserveContent',] }], |
| disabled: [{ type: Input, args: ['cdkObserveContentDisabled',] }], |
| debounce: [{ type: Input }] |
| }; |
| class ObserversModule { |
| } |
| ObserversModule.decorators = [ |
| { type: NgModule, args: [{ |
| exports: [CdkObserveContent], |
| declarations: [CdkObserveContent], |
| providers: [MutationObserverFactory] |
| },] }, |
| ]; |
| |
| /** |
| * @fileoverview added by tsickle |
| * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc |
| */ |
| |
| /** |
| * @fileoverview added by tsickle |
| * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc |
| */ |
| |
| export { MutationObserverFactory, ContentObserver, CdkObserveContent, ObserversModule }; |
| //# sourceMappingURL=observers.js.map |