editor.js/src/components/modules/listeners.ts
Peter Savchenko 63eeec0f3b
Release / 2.18 (#1181)
Co-authored-by: George Berezhnoy <gohabereg@users.noreply.github.com>
Co-authored-by: Georgy Berezhnoy <gohabereg@gmail.com>
Co-authored-by: tasuku-s <tasuku@freemind.co.jp>
Co-authored-by: Athul Anil Kumar <athul7744@outlook.com>
Co-authored-by: Taly <vitalik7tv@yandex.ru>
Co-authored-by: flaming-cl <51183663+flaming-cl@users.noreply.github.com>
Co-authored-by: Nguyen Ngoc Son <sonnn.se@gmail.com>
Co-authored-by: Sisir Das K <37764463+sis-dk@users.noreply.github.com>
Co-authored-by: Sisir <sisir@hellosivi.com>
2020-06-03 11:17:29 +03:00

215 lines
5.5 KiB
TypeScript

import Module from '../__module';
/**
* Event listener information
*
* @interface ListenerData
*/
export interface ListenerData {
/**
* 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 module
*
* @module Listeners
*
* Module-decorator for event listeners assignment
*
* @author Codex Team
* @version 2.0.0
*/
/**
* @typedef {Listeners} Listeners
* @property {ListenerData[]} allListeners - listeners store
*/
export default class Listeners extends Module {
/**
* Stores all listeners data to find/remove/process it
*
* @type {ListenerData[]}
*/
private allListeners: ListenerData[] = [];
/**
* Assigns event listener on element
*
* @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
): void {
const assignedEventData = {
element,
eventType,
handler,
options,
};
const alreadyExist = this.findOne(element, eventType, handler);
if (alreadyExist) {
return;
}
this.allListeners.push(assignedEventData);
element.addEventListener(eventType, handler, options);
}
/**
* 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,
options?: boolean | AddEventListenerOptions
): void {
const existingListeners = this.findAll(element, eventType, handler);
existingListeners.forEach((listener, i) => {
const index = this.allListeners.indexOf(existingListeners[i]);
if (index > 0) {
this.allListeners.splice(index, 1);
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;
}
});
}
}