UNPKG

dom-observe

Version:

![npm](https://img.shields.io/npm/v/dom-observe?style=for-the-badge)![npm](https://img.shields.io/npm/dw/dom-observe?style=for-the-badge)![npm](https://img.shields.io/npm/dt/dom-observe?style=for-the-badge) ![node](https://img.shields.io/node/v/dom-observ

172 lines (140 loc) 6.09 kB
import { OnAppearEventListenerCallback, OnChangeEventListenerCallback, OnStartEventListenerCallback, OnStopEventListenerCallback, SelectorCallback } from "./callbacks"; import {EventEmitter} from "events"; import {OnDisappearEventListenerCallback} from "./callbacks/OnDisappearEventListenerCallback"; import {IDOMObserverInitParameters} from "./parameters/IDOMObserverInitParameters"; import {setImmediate, sleep} from "delay-me"; export class DOMObserver<T extends Element = Element>{ private readonly emitter: EventEmitter = new EventEmitter(); private readonly selector: SelectorCallback<T>; private observer: MutationObserver = null; private _is_active: boolean = false; public get isActive(): boolean{ return this._is_active; } private _parameters: IDOMObserverInitParameters<T> = null; public get parameters(): IDOMObserverInitParameters<T>{ return Object.assign({}, this._parameters); } private _state: 'appeared'|'disappeared' = 'disappeared'; private $elementRef: T = null; /** * @param {SelectorCallback<T>} selector * @param {IDOMObserverInitParameters<T>>} parameters */ constructor(selector: SelectorCallback<T>, parameters: IDOMObserverInitParameters<T>) { this._parameters = parameters; this.selector = selector; this.observeProcess = this.observeProcess.bind(this); this.onMutationOccurred = this.onMutationOccurred.bind(this); } /** * Starts DOM observation */ public start(): void{ if(this._is_active) return; this._is_active = true; this.emit('start'); setImmediate(this.observeProcess); } /** * Stops DOM observation */ public stop(): void{ if(!this._is_active) return; this._is_active = false; this.observer.disconnect(); this.observer = null; this.emit('stop'); } /** * @returns {Promise<void>} * @protected */ protected async observeProcess() { if(!this._is_active) return; switch(this._state){ case 'appeared': { if(this.$elementRef === null || !document.contains(this.$elementRef)){ this._state = 'disappeared'; if(this.observer !== null){ this.observer.disconnect(); this.observer = null; } const $element = this.$elementRef; this.$elementRef = null; this.emit('disappear', $element as T); } } break; case 'disappeared': { let $element = this.selector.apply(null, []); if($element !== null){ this._state = 'appeared'; this.$elementRef = $element; this.emit('appear', $element as T); if(this.observer !== null){ this.observer.disconnect(); this.observer = null; } if(!this._is_active) return; this.observer = new MutationObserver(this.onMutationOccurred); this.observer.observe(this.$elementRef, this._parameters); } } break; } if(this._is_active) { await sleep(this.parameters.interval); setImmediate(this.observeProcess); } } /** * @param {MutationRecord[]} mutations * @protected */ protected onMutationOccurred(mutations: MutationRecord[]): void{ if(!this._is_active) return; this.emit('change', this.$elementRef as T, mutations); } //region Events protected emit(event: 'start'): void; protected emit(event: 'appear', $element: T): void; protected emit(event: 'change', $element: T, mutations: MutationRecord[]): void; protected emit(event: 'disappear', $element: T): void; protected emit(event: 'stop'): void; protected emit(event: string, ...args: any[]): void{ this.emitter.emit(event, ...args); } public on(event: 'start', listener: OnStartEventListenerCallback): DOMObserver<T>; public on(event: 'appear', listener: OnAppearEventListenerCallback<T>): DOMObserver<T>; public on(event: 'change', listener: OnChangeEventListenerCallback<T>): DOMObserver<T>; public on(event: 'disappear', listener: OnDisappearEventListenerCallback<T>): DOMObserver<T>; public on(event: 'stop', listener: OnStopEventListenerCallback): DOMObserver<T>; public on(event: string, listener: {(...args: any[]): any;}): DOMObserver<T>{ this.emitter.on(event, listener); return this; } public once(event: 'start', listener: OnStartEventListenerCallback): DOMObserver<T>; public once(event: 'appear', listener: OnAppearEventListenerCallback<T>): DOMObserver<T>; public once(event: 'change', listener: OnChangeEventListenerCallback<T>): DOMObserver<T>; public once(event: 'disappear', listener: OnDisappearEventListenerCallback<T>): DOMObserver<T>; public once(event: 'stop', listener: OnStopEventListenerCallback): DOMObserver<T>; public once(event: string, listener: {(...args: any[]): any;}): DOMObserver<T>{ this.emitter.once(event, listener); return this; } public off(event: 'start', listener: OnStartEventListenerCallback): DOMObserver<T>; public off(event: 'appear', listener: OnAppearEventListenerCallback<T>): DOMObserver<T>; public off(event: 'change', listener: OnChangeEventListenerCallback<T>): DOMObserver<T>; public off(event: 'disappear', listener: OnDisappearEventListenerCallback<T>): DOMObserver<T>; public off(event: 'stop', listener: OnStopEventListenerCallback): DOMObserver<T>; public off(event: string, listener: {(...args: any[]): any;}): DOMObserver<T>{ this.emitter.off(event, listener); return this; } //endregion }