/**
* @archivo src/js/event-target.js
* /
importar * como Eventos desde './utils/events.js';
importar ventana desde 'global/window';
/**
* `EventTarget` es una clase que puede tener la misma API que DOM `EventTarget`. Él
* agrega funciones abreviadas que envuelven funciones largas. Por ejemplo:
* la función `on` es un envoltorio alrededor de `addEventListener`.
*
* @ver [EventTarget Spec]{@link https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget}
* @clase EventObjetivo
* /
const EventTarget = function() {};
/**
* Un evento DOM personalizado.
*
* @typedef {Objeto} Objetivo de evento ~ Evento
* @ver [Propiedades]{@enlace https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent}
* /
/**
* Todos los oyentes de eventos deben seguir el siguiente formato.
*
* @callback EventObjetivo ~ EventListener
* @este {objetivo de evento}
*
* @param {EventTarget~Evento} evento
* el evento que activó esta función
*
* @param {Objeto} [hash]
* hash de datos enviados durante el evento
* /
/**
* Un objeto que contiene nombres de eventos como claves y booleanos como valores.
*
* > NOTA: Si el nombre de un evento se establece en un valor verdadero aquí {@link EventTarget#trigger}
* tendrá funcionalidad extra. Consulte esa función para obtener más información.
*
* @property EventTarget.prototype.allowedEvents_
* @privado
* /
EventTarget.prototype.allowedEvents_ = {};
/**
* Agrega un `escucha de eventos` a una instancia de un `EventTarget`. Un `escucha de eventos` es un
* función que se llamará cuando se active un evento con un nombre determinado.
*
* @param {cadena|cadena[]} tipo
* Un nombre de evento o una matriz de nombres de eventos.
*
* @param {EventTarget~EventListener} fn
* La función para llamar con `EventTarget`s
* /
EventTarget.prototype.on = función (tipo, fn) {
// Eliminar el alias addEventListener antes de llamar a Events.on
// para que no entremos en un bucle de tipo infinito
const ael = this.addEventListener;
this.addEventListener = () => {};
Eventos.on(esto, tipo, fn);
this.addEventListener = ael;
};
/**
* Un alias de {@link EventTarget#on}. Permite que `EventTarget` imite
* la API DOM estándar.
*
* @función
* @ver {@link EventTarget#on}
* /
EventTarget.prototype.addEventListener = EventTarget.prototype.on;
/**
* Elimina un `escucha de eventos` para un evento específico de una instancia de `EventTarget`.
* Esto hace que el `event listener` ya no sea llamado cuando el
* Sucede el evento nombrado.
*
* @param {cadena|cadena[]} tipo
* Un nombre de evento o una matriz de nombres de eventos.
*
* @param {EventTarget~EventListener} fn
* La función de eliminar.
* /
EventTarget.prototype.off = función (tipo, fn) {
Eventos.off(esto, tipo, fn);
};
/**
* Un alias de {@link EventTarget#off}. Permite que `EventTarget` imite
* la API DOM estándar.
*
* @función
* @ver {@link EventTarget#off}
* /
EventTarget.prototype.removeEventListener = EventTarget.prototype.off;
/**
* Esta función agregará un "escucha de eventos" que se activa solo una vez. Después de la
* primer activador se eliminará. Esto es como agregar un `escucha de eventos`
* con {@link EventTarget#on} que llama {@link EventTarget#off} sobre sí mismo.
*
* @param {cadena|cadena[]} tipo
* Un nombre de evento o una matriz de nombres de eventos.
*
* @param {EventTarget~EventListener} fn
* La función que se llamará una vez para cada nombre de evento.
* /
EventTarget.prototype.one = función (tipo, fn) {
// Eliminar el alias de addEventListener Events.on
// para que no entremos en un bucle de tipo infinito
const ael = this.addEventListener;
this.addEventListener = () => {};
Eventos.uno(esto, tipo, fn);
this.addEventListener = ael;
};
EventTarget.prototype.any = función (tipo, fn) {
// Eliminar el alias de addEventListener Events.on
// para que no entremos en un bucle de tipo infinito
const ael = this.addEventListener;
this.addEventListener = () => {};
Eventos.cualquiera(esto, tipo, fn);
this.addEventListener = ael;
};
/**
* Esta función hace que suceda un evento. Esto hará que cualquier 'escucha de eventos'
* que están esperando ese evento, para ser llamados. Si no hay 'escuchadores de eventos'
* para un evento entonces no pasará nada.
*
* Si el nombre del `Evento` que se activa está en `EventTarget.allowedEvents_`.
* Trigger también llamará a la función `on` + `uppercaseEventName`.
*
* Ejemplo:
* 'clic' está en `EventTarget.allowedEvents_`, por lo tanto, el disparador intentará llamar
* `onClick` si existe.
*
* @param {string|EventTarget~Event|Object} evento
* El nombre del evento, un 'Evento' o un objeto con una clave de tipo establecida en
* un nombre de evento.
* /
EventTarget.prototype.trigger = función (evento) {
const tipo = evento.tipo || evento;
// desaprobación
// En una versión futura, deberíamos tener como destino predeterminado `this`
// similar a cómo por defecto el objetivo es `elem` en
// `Eventos.trigger`. En este momento, el "objetivo" predeterminado será
// `document` debido a la llamada `Event.fixEvent`.
if (tipo de evento === 'cadena') {
evento = {tipo};
}
evento = Eventos.fixEvent(evento);
if (this.allowedEvents_[tipo] && este['en' + tipo]) {
este['en' + tipo](evento);
}
Eventos.trigger(este, evento);
};
/**
* Un alias de {@link EventTarget#trigger}. Permite que `EventTarget` imite
* la API DOM estándar.
*
* @función
* @ver {@link EventTarget#trigger}
* /
EventTarget.prototype.dispatchEvent = EventTarget.prototype.trigger;
dejar EVENT_MAP;
EventTarget.prototype.queueTrigger = función (evento) {
// solo configure EVENT_MAP si se usará
si (!EVENTO_MAPA) {
EVENT_MAP = nuevo Mapa();
}
const tipo = evento.tipo || evento;
let map = EVENT_MAP.get(this);
si (!mapa) {
mapa = nuevo Mapa();
EVENT_MAP.set(esto, mapa);
}
const oldTimeout = map.get(tipo);
map.delete(tipo);
ventana.clearTimeout(oldTimeout);
const tiempo de espera = ventana.setTimeout(() => {
map.delete(tipo);
// si eliminamos todos los tiempos de espera para el objetivo actual, eliminamos su mapa
if (mapa.tamaño === 0) {
mapa = nulo;
EVENT_MAP.delete(esto);
}
this.trigger(evento);
}, 0);
map.set(tipo, tiempo de espera);
};
exportar EventTarget por defecto;