editor.js/src/components/utils/listeners.ts
Peter Savchenko 3272efc3f7
chore(linting): eslint updated, code linted (#2174)
* update eslint + autofix

* a bunch of eslint fixes

* some spelling & eslint fixes

* fix some eslint errors and spells

* Update __module.ts

* a bunch of eslint fixes in tests

* Update cypress.yml

* Update cypress.yml

* fix cypress docker image name

* fixes for tests

* more tests fixed

* rm rule ignore

* rm another ignored rule

* Update .eslintrc
2022-11-25 21:56:50 +04:00

243 lines
6.2 KiB
TypeScript

import * as _ from '../utils';
/**
* Event listener information
*
* @interface ListenerData
*/
export interface ListenerData {
/**
* Listener unique identifier
*/
id: string;
/**
* Element where to listen to dispatched events
*/
element: EventTarget;
/**
* Event to listen
*/
eventType: string;
/**
* Event handler
*
* @param {Event} event - event object
*/
handler: (event: Event) => void;
/**
* @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
*/
options: boolean | AddEventListenerOptions;
}
/**
* Editor.js Listeners helper
*
* Decorator for event listeners assignment
*
* @author Codex Team
* @version 2.0.0
*/
/**
* @typedef {Listeners} Listeners
* @property {ListenerData[]} allListeners - listeners store
*/
export default class Listeners {
/**
* Stores all listeners data to find/remove/process it
*
* @type {ListenerData[]}
*/
private allListeners: ListenerData[] = [];
/**
* Assigns event listener on element and returns unique identifier
*
* @param {EventTarget} element - DOM element that needs to be listened
* @param {string} eventType - event type
* @param {Function} handler - method that will be fired on event
* @param {boolean|AddEventListenerOptions} options - useCapture or {capture, passive, once}
*/
public on(
element: EventTarget,
eventType: string,
handler: (event: Event) => void,
options: boolean | AddEventListenerOptions = false
): string {
const id = _.generateId('l');
const assignedEventData = {
id,
element,
eventType,
handler,
options,
};
const alreadyExist = this.findOne(element, eventType, handler);
if (alreadyExist) {
return;
}
this.allListeners.push(assignedEventData);
element.addEventListener(eventType, handler, options);
return id;
}
/**
* Removes event listener from element
*
* @param {EventTarget} element - DOM element that we removing listener
* @param {string} eventType - event type
* @param {Function} handler - remove handler, if element listens several handlers on the same event type
* @param {boolean|AddEventListenerOptions} options - useCapture or {capture, passive, once}
*/
public off(
element: EventTarget,
eventType: string,
handler?: (event: Event) => void,
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
options?: boolean | AddEventListenerOptions
): void {
const existingListeners = this.findAll(element, eventType, handler);
existingListeners.forEach((listener, i) => {
const index = this.allListeners.indexOf(existingListeners[i]);
if (index > -1) {
this.allListeners.splice(index, 1);
listener.element.removeEventListener(listener.eventType, listener.handler, listener.options);
}
});
}
/**
* Removes listener by id
*
* @param {string} id - listener identifier
*/
public offById(id: string): void {
const listener = this.findById(id);
if (!listener) {
return;
}
listener.element.removeEventListener(listener.eventType, listener.handler, listener.options);
}
/**
* Finds and returns first listener by passed params
*
* @param {EventTarget} element - event target
* @param {string} [eventType] - event type
* @param {Function} [handler] - event handler
* @returns {ListenerData|null}
*/
public findOne(element: EventTarget, eventType?: string, handler?: (event: Event) => void): ListenerData {
const foundListeners = this.findAll(element, eventType, handler);
return foundListeners.length > 0 ? foundListeners[0] : null;
}
/**
* Return all stored listeners by passed params
*
* @param {EventTarget} element - event target
* @param {string} eventType - event type
* @param {Function} handler - event handler
* @returns {ListenerData[]}
*/
public findAll(element: EventTarget, eventType?: string, handler?: (event: Event) => void): ListenerData[] {
let found;
const foundByEventTargets = element ? this.findByEventTarget(element) : [];
if (element && eventType && handler) {
found = foundByEventTargets.filter((event) => event.eventType === eventType && event.handler === handler);
} else if (element && eventType) {
found = foundByEventTargets.filter((event) => event.eventType === eventType);
} else {
found = foundByEventTargets;
}
return found;
}
/**
* Removes all listeners
*/
public removeAll(): void {
this.allListeners.map((current) => {
current.element.removeEventListener(current.eventType, current.handler, current.options);
});
this.allListeners = [];
}
/**
* Module cleanup on destruction
*/
public destroy(): void {
this.removeAll();
}
/**
* Search method: looks for listener by passed element
*
* @param {EventTarget} element - searching element
* @returns {Array} listeners that found on element
*/
private findByEventTarget(element: EventTarget): ListenerData[] {
return this.allListeners.filter((listener) => {
if (listener.element === element) {
return listener;
}
});
}
/**
* Search method: looks for listener by passed event type
*
* @param {string} eventType - event type
* @returns {ListenerData[]} listeners that found on element
*/
private findByType(eventType: string): ListenerData[] {
return this.allListeners.filter((listener) => {
if (listener.eventType === eventType) {
return listener;
}
});
}
/**
* Search method: looks for listener by passed handler
*
* @param {Function} handler - event handler
* @returns {ListenerData[]} listeners that found on element
*/
private findByHandler(handler: (event: Event) => void): ListenerData[] {
return this.allListeners.filter((listener) => {
if (listener.handler === handler) {
return listener;
}
});
}
/**
* Returns listener data found by id
*
* @param {string} id - listener identifier
* @returns {ListenerData}
*/
private findById(id: string): ListenerData {
return this.allListeners.find((listener) => listener.id === id);
}
}