import {ElementRef} from '@angular/core'; import extend from 'lodash-es/extend'; import {IncrementalStackManager} from '@ex-helpers/stack'; import {bounds} from './bounds'; declare module '@angular/core' { class ElementRef { private _watchSizeCollection: any; nativeElement: T; constructor(nativeElement: T); watchSize: (callback: (height: number, width: number) => void, options?: { attributes: boolean, childList: boolean, characterData: boolean }, params?: { legacy: boolean, timeout?: number }) => () => void; watchChanges: (callback: MutationCallback, options: MutationObserverInit) => () => void; triggerSizeCheck: () => void; } } interface SizeCollectionItem { triggerCheck: () => void; startCountdown: () => void; callback: (height: number, width: number) => void; observer?: MutationObserver; id?: number; legacy?: boolean; } const DEFAULT_OPTIONS = { attributes: true, childList: true, characterData: true }; ElementRef.prototype.watchSize = function (callback: (height: number, width: number) => void, options?: { attributes?: boolean, childList?: boolean, characterData?: boolean }, params: { timeout?: number, legacy: boolean } = {legacy: false}) { if (!this._watchSizeCollection) { Object.defineProperty(this, '_watchSizeCollection', { enumerable: false, configurable: true, writable: false, value: new IncrementalStackManager('id') }); } options = extend(DEFAULT_OPTIONS, options); let timeout: any; let lastHeight: number; let lastWidth: number; const triggerCheck = () => { const sizes = bounds(this.nativeElement).size; if (lastWidth === sizes.width && lastHeight === sizes.height) { return; } lastHeight = sizes.height; lastWidth = sizes.width; callback(sizes.height, sizes.width); }; const startCountdown = () => { clearTimeout(timeout); timeout = setTimeout(() => { triggerCheck(); }, params.timeout || 100); }; const item = this._watchSizeCollection.add({ callback, startCountdown, triggerCheck }); if (MutationObserver && params.legacy === false) { const observer = new MutationObserver(mutations => { startCountdown(); }); item.observer = observer; item.legacy = false; startCountdown(); observer.observe(this.nativeElement, options); return () => observer.disconnect(); } else { item.legacy = true; const checkInterval = setInterval(() => { triggerCheck(); }, 200); startCountdown(); return () => clearInterval(checkInterval); } }; ElementRef.prototype.triggerSizeCheck = function () { if (this._watchSizeCollection) { this._watchSizeCollection.execute('triggerCheck'); } }; ElementRef.prototype.watchChanges = function (callback: MutationCallback, options: MutationObserverInit) { if (MutationObserver) { const observer = new MutationObserver(callback); observer.observe(this.nativeElement, options); return () => observer.disconnect(); } return () => { }; };