import {ElementRef} from '@angular/core'; import extend from 'lodash-es/extend'; import {IncrementalStackManager} from '@ex-helpers/stack'; import {bounds} from './bounds'; 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 }; export class ElementWatcher { private _watchSizeCollection: any; public nativeElement: HTMLElement; constructor(ref: HTMLElement | ElementRef) { this.nativeElement = ref instanceof ElementRef ? ref.nativeElement : ref; } watchSize(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); } } triggerSizeCheck() { if (this._watchSizeCollection) { this._watchSizeCollection.execute('triggerCheck'); } } watchChanges(callback: MutationCallback, options: MutationObserverInit) { if (MutationObserver) { const observer = new MutationObserver(callback); observer.observe(this.nativeElement, options); return () => observer.disconnect(); } return () => { }; } } export function watchElement(ref: HTMLElement | ElementRef) { return new ElementWatcher(ref); }