dom-observe
Version:
  • 6.09 kB
text/typescript
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
}