/**
* @archivo mixins/evented.js
* @module evento
* /
importar ventana desde 'global/window';
importar * como Dom desde '../utils/dom';
importar * como Eventos desde '../utils/events';
importar * como Fn desde '../utils/fn';
importar * como Obj desde '../utils/obj';
importar EventTarget desde '../event-target';
importar DomData desde '../utils/dom-data';
importar registro desde '../utils/log';
const objNombre = (obj) => {
if (tipo de obj.nombre === 'función') {
return obj.nombre();
}
if (tipo de obj.nombre === 'cadena') {
return obj.nombre;
}
if (obj.nombre_) {
return obj.nombre_;
}
if (obj.constructor && obj.constructor.nombre) {
return obj.constructor.nombre;
}
tipo de retorno de obj;
};
/**
* Devuelve si a un objeto se le ha aplicado o no la combinación de eventos.
*
* @param {Objeto} objeto
* Un objeto para probar.
*
* @return {booleano}
* Si el objeto parece estar o no evento.
* /
const isEvented = (objeto) =>
instancia de objeto de EventTarget ||
!!objeto.eventBusEl_ &&
['encendido', 'uno', 'apagado', 'disparador'].cada(k => tipo de objeto[k] === 'función');
/**
* Agrega una devolución de llamada para que se ejecute después de que se aplique la combinación de eventos.
*
* @param {Objeto} objeto
* Un objeto para agregar
* @param {Función} devolución de llamada
* La devolución de llamada para ejecutar.
* /
const addEventedCallback = (objetivo, devolución de llamada) => {
si (es un evento (objetivo)) {
llamar de vuelta();
} else {
if (!target.eventedCallbacks) {
target.eventedCallbacks = [];
}
target.eventedCallbacks.push(devolución de llamada);
}
};
/**
* Si un valor es un tipo de evento válido: cadena o matriz no vacía.
*
* @privado
* @param {cadena|Array} tipo
* El valor de tipo a probar.
*
* @return {booleano}
* Si el tipo es o no un tipo de evento válido.
* /
const esValidEventType = (tipo) =>
// La expresión regular aquí verifica que el `tipo` contiene al menos un no-
// carácter de espacio en blanco.
(tipo de tipo === 'cadena' && (/\S/).prueba(tipo)) ||
(Array.isArray(tipo) && !!tipo.longitud);
/**
* Valida un valor para determinar si es un objetivo de evento válido. Tira si no.
*
* @privado
* @throws {Error}
* Si el objetivo no parece ser un objetivo de evento válido.
*
* @param {Objeto} objetivo
* El objeto a probar.
*
* @param {Objeto} obj
* El objeto con eventos que estamos validando
*
* @param {cadena} fnName
* El nombre de la función mixin con eventos que llamó a esto.
* /
const validarTarget = (objetivo, obj, fnName) => {
if (!objetivo || (!objetivo.nombreNodo && !isEvented(objetivo))) {
throw new Error(`Objetivo no válido para ${objName(obj)}#${fnName}; debe ser un nodo DOM o un objeto con eventos.`);
}
};
/**
* Valida un valor para determinar si es un objetivo de evento válido. Tira si no.
*
* @privado
* @throws {Error}
* Si el tipo no parece ser un tipo de evento válido.
*
* @param {cadena|Array} tipo
* El tipo a probar.
*
* @param {Objeto} obj
* El objeto con eventos que estamos validando
*
* @param {cadena} fnName
* El nombre de la función mixin con eventos que llamó a esto.
* /
const validarEventType = (tipo, obj, fnName) => {
if (!isValidEventType(tipo)) {
throw new Error(`Tipo de evento no válido para ${objName(obj)}#${fnName}; debe ser una cadena o matriz no vacía.`);
}
};
/**
* Valida un valor para determinar si es un oyente válido. Tira si no.
*
* @privado
* @throws {Error}
* Si el oyente no es una función.
*
* @param {Función} oyente
* El oyente a prueba.
*
* @param {Objeto} obj
* El objeto con eventos que estamos validando
*
* @param {cadena} fnName
* El nombre de la función mixin con eventos que llamó a esto.
* /
const validarEscucha = (escucha, obj, fnName) => {
if (tipo de oyente! == 'función') {
throw new Error(`Oyente no válido para ${objName(obj)}#${fnName}; debe ser una función.`);
}
};
/**
* Toma una serie de argumentos dados a `on()` o `one()`, los valida y
* los normaliza en un objeto.
*
* @privado
* @param {Objeto} propio
* El objeto con evento en el que se llamó `on()` o `one()`. Esto
* El objeto se vinculará como el valor `this` para el oyente.
*
* @param {Array} argumentos
* Una matriz de argumentos pasados a `on()` o `one()`.
*
* @param {cadena} fnName
* El nombre de la función mixin con eventos que llamó a esto.
*
* @return {Objeto}
* Un objeto que contiene valores útiles para las llamadas `on()` o `one()`.
* /
const normalizeListenArgs = (self, args, fnName) => {
// Si el número de argumentos es inferior a 3, el destino siempre es el
// objeto con eventos en sí mismo.
const esTargetingSelf = argumentos.longitud < 3 || argumentos[0] === yo || args[0] === self.eventBusEl_;
dejar objetivo;
dejar escribir;
deja que el oyente;
if (esTargetingSelf) {
objetivo = self.eventBusEl_;
// Tratar los casos en los que obtuvimos 3 argumentos, pero todavía estamos escuchando
// el propio objeto del evento.
if (args.longitud > = 3) {
argumentos.shift();
}
[tipo, oyente] = argumentos;
} else {
[objetivo, tipo, oyente] = argumentos;
}
validarTarget(objetivo, self, fnName);
validarEventType(tipo, self, fnName);
validarEscucha(oyente, self, fnName);
oyente = Fn.bind(self, oyente);
return {isTargetingSelf, target, type, listener};
};
/**
* Agrega el oyente a los tipos de eventos en el objetivo, normalizando para
* el tipo de objetivo.
*
* @privado
* @param {Elemento|Objeto} destino
* Un nodo DOM u objeto con eventos.
*
* Método @param {cadena}
* El método de vinculación de eventos a usar ("on" o "one").
*
* @param {cadena|Array} tipo
* Uno o más tipos de eventos.
*
* @param {Función} oyente
* Una función de oyente.
* /
const listen = (objetivo, método, tipo, oyente) => {
validarTarget(objetivo, objetivo, método);
if (objetivo.nombreNodo) {
Eventos[método](objetivo, tipo, oyente);
} else {
objetivo[método](tipo, oyente);
}
};
/**
* Contiene métodos que proporcionan capacidades de eventos a un objeto que se pasa
* a {@link module:evented|evented}.
*
* @mixin EventedMixin
* /
const EventedMixin = {
/**
* Agregue un oyente a un evento (o eventos) en este objeto u otro evento
* objeto.
*
* @param {cadena|Array|Element|Object} targetOrType
* Si se trata de una cadena o matriz, representa los tipos de eventos
* que activará al oyente.
*
* En su lugar, se puede pasar aquí otro objeto con eventos, que
* hacer que el oyente escuche eventos en _ese_ objeto.
*
* En cualquier caso, el valor `this` del oyente estará vinculado a
* este objeto.
*
* @param {cadena|Array|Función} typeOrListener
* Si el primer argumento era una cadena o una matriz, este debería ser el
* Función de escucha. De lo contrario, esta es una cadena o matriz de eventos.
* tipo(s).
*
* @param {Función} [oyente]
* Si el primer argumento fue otro objeto con evento, este será
* la función de oyente.
* /
en (... argumentos) {
const {isTargetingSelf, target, type, listener} = normalizeListenArgs(this, args, 'on');
escuchar (objetivo, 'encendido', tipo, oyente);
// Si este objeto está escuchando a otro objeto con eventos.
if (!isTargetingSelf) {
// Si se desecha este objeto, elimine el oyente.
const removeListenerOnDispose = () => this.off(objetivo, tipo, oyente);
// Use el mismo ID de función que el oyente para que podamos eliminarlo más tarde.
// usando la ID del oyente original.
removeListenerOnDispose.guid = oyente.guid;
// Agregue también un oyente al evento de disposición del objetivo. Esto asegura
// que si el objetivo se desecha ANTES de este objeto, eliminamos el
// escucha de eliminación que se acaba de agregar. De lo contrario, creamos una pérdida de memoria.
const removeRemoverOnTargetDispose = () => this.off('dispose', removeListenerOnDispose);
// Use el mismo ID de función que el oyente para que podamos eliminarlo más tarde
// usando la ID del oyente original.
removeRemoverOnTargetDispose.guid = oyente.guid;
listen(this, 'on', 'dispose', removeListenerOnDispose);
listen(objetivo, 'on', 'dispose', removeRemoverOnTargetDispose);
}
},
/**
* Agregue un oyente a un evento (o eventos) en este objeto u otro evento
* objeto. El agente de escucha se llamará una vez por evento y, a continuación, se eliminará.
*
* @param {cadena|Array|Element|Object} targetOrType
* Si se trata de una cadena o matriz, representa los tipos de eventos
* que activará al oyente.
*
* En su lugar, se puede pasar aquí otro objeto con eventos, que
* hacer que el oyente escuche eventos en _ese_ objeto.
*
* En cualquier caso, el valor `this` del oyente estará vinculado a
* este objeto.
*
* @param {cadena|Array|Función} typeOrListener
* Si el primer argumento era una cadena o una matriz, este debería ser el
* Función de escucha. De lo contrario, esta es una cadena o matriz de eventos.
* tipo(s).
*
* @param {Función} [oyente]
* Si el primer argumento fue otro objeto con evento, este será
* la función de oyente.
* /
uno (... argumentos) {
const {isTargetingSelf, target, type, listener} = normalizeListenArgs(this, args, 'one');
// Apuntando a este objeto con eventos.
if (esTargetingSelf) {
listen(objetivo, 'uno', tipo, oyente);
// Apuntando a otro objeto con eventos.
} else {
// HACER: ¡Este envoltorio es incorrecto! solo debe
// elimina el envoltorio del tipo de evento que lo llamó.
// ¡En cambio, todos los oyentes se eliminan en el primer disparo!
// ver https://github.com/videojs/video.js/issues/5962
contenedor const = (...largos) => {
this.off(objetivo, tipo, envoltorio);
listener.apply(null, largs);
};
// Use el mismo ID de función que el oyente para que podamos eliminarlo más tarde
// usando la ID del oyente original.
contenedor.guid = oyente.guid;
listen(objetivo, 'uno', tipo, envoltorio);
}
},
/**
* Agregue un oyente a un evento (o eventos) en este objeto u otro evento
* objeto. El oyente solo será llamado una vez para el primer evento que se active
* luego eliminado.
*
* @param {cadena|Array|Element|Object} targetOrType
* Si se trata de una cadena o matriz, representa los tipos de eventos
* que activará al oyente.
*
* En su lugar, se puede pasar aquí otro objeto con eventos, que
* hacer que el oyente escuche eventos en _ese_ objeto.
*
* En cualquier caso, el valor `this` del oyente estará vinculado a
* este objeto.
*
* @param {cadena|Array|Función} typeOrListener
* Si el primer argumento era una cadena o una matriz, este debería ser el
* Función de escucha. De lo contrario, esta es una cadena o matriz de eventos.
* tipo(s).
*
* @param {Función} [oyente]
* Si el primer argumento fue otro objeto con evento, este será
* la función de oyente.
* /
cualquiera (...argumentos) {
const {isTargetingSelf, target, type, listener} = normalizeListenArgs(this, args, 'any');
// Apuntando a este objeto con eventos.
if (esTargetingSelf) {
listen(objetivo, 'cualquiera', tipo, oyente);
// Apuntando a otro objeto con eventos.
} else {
contenedor const = (...largos) => {
this.off(objetivo, tipo, envoltorio);
listener.apply(null, largs);
};
// Use el mismo ID de función que el oyente para que podamos eliminarlo más tarde
// usando la ID del oyente original.
contenedor.guid = oyente.guid;
listen(objetivo, 'cualquiera', tipo, envoltorio);
}
},
/**
* Elimina los oyentes de los eventos en un objeto con eventos.
*
* @param {cadena|Matriz|Elemento|Objeto} [targetOrType]
* Si se trata de una cadena o matriz, representa los tipos de eventos.
*
* Aquí se puede pasar otro objeto con evento, en cuyo caso
* TODOS LOS 3 argumentos son _requeridos_.
*
* @param {cadena|Array|Función} [tipoOrListener]
* Si el primer argumento fue una cadena o una matriz, este puede ser el
* Función de escucha. De lo contrario, esta es una cadena o matriz de eventos.
* tipo(s).
*
* @param {Función} [oyente]
* Si el primer argumento fue otro objeto con evento, este será
* la función de oyente; de lo contrario, _todos_ los oyentes vinculados al
* Se eliminarán los tipos de eventos.
* /
off(targetOrType, typeOrListener, listener) {
// Apuntando a este objeto con eventos.
if (!targetOrType || isValidEventType(targetOrType)) {
Events.off(this.eventBusEl_, targetOrType, typeOrListener);
// Apuntando a otro objeto con eventos.
} else {
const target = targetOrType;
const tipo = typeOrListener;
// ¡Falla rápido y de manera significativa!
validarTarget(objetivo, esto, 'apagado');
validarEventType(tipo, esto, 'apagado');
validarEscucha(escucha, esto, 'apagado');
// Asegúrese de que haya al menos un GUID, incluso si la función no se ha utilizado
oyente = Fn.bind(esto, oyente);
// Eliminar el detector de disposición en este objeto con eventos, que se proporcionó
// el mismo GUID que el detector de eventos en on().
this.off('dispose', oyente);
if (objetivo.nombreNodo) {
Events.off(objetivo, tipo, oyente);
Events.off(objetivo, 'disponer', oyente);
} más si (es un evento (objetivo)) {
target.off(tipo, oyente);
target.off('dispose', oyente);
}
}
},
/**
* Activar un evento en este objeto con evento, lo que hace que se llame a sus oyentes.
*
* @param {cadena|Objeto} evento
* Un tipo de evento o un objeto con una propiedad de tipo.
*
* @param {Objeto} [hash]
* Un objeto adicional para pasar a los oyentes.
*
* @return {booleano}
* Si se evitó o no el comportamiento predeterminado.
* /
disparador (evento, hash) {
validarTarget(this.eventBusEl_, this, 'trigger');
tipo const = evento && tipo de evento !== 'cadena' ? evento.tipo : evento;
if (!isValidEventType(tipo)) {
const error = `Tipo de evento no válido para ${objName(this)}#trigger; ` +
'debe ser una cadena u objeto no vacío con una clave de tipo que tiene un valor no vacío.';
si (evento) {
(this.log || log).error(error);
} else {
lanzar un nuevo error (error);
}
}
return Events.trigger(this.eventBusEl_, evento, hash);
}
};
/**
* Aplica {@link module:evented~EventedMixin|EventedMixin} a un objeto de destino.
*
* @param {Objeto} objetivo
* El objeto al que agregar métodos de evento.
*
* @param {Objeto} [opciones={}]
* Opciones para personalizar el comportamiento de mixin.
*
* @param {cadena} [opciones.eventBusKey]
* De forma predeterminada, agrega un elemento DOM `eventBusEl_` al objeto de destino,
* que se utiliza como bus de eventos. Si el objeto de destino ya tiene un
* Elemento DOM que debe usarse, pase su clave aquí.
*
* @return {Objeto}
* El objeto de destino.
* /
función evented(objetivo, opciones = {}) {
const {eventBusKey} = opciones;
// Establecer o crear el eventoBusEl_.
si (clave de bus de eventos) {
if (!target[eventoBusClave].nodoNombre) {
throw new Error(`La eventBusKey "${eventBusKey}" no hace referencia a un elemento.`);
}
target.eventBusEl_ = target[eventBusKey];
} else {
target.eventBusEl_ = Dom.createEl('span', {className: 'vjs-event-bus'});
}
Obj.assign(objetivo, EventedMixin);
if (objetivo.eventedCallbacks) {
target.eventedCallbacks.forEach((devolución de llamada) => {
llamar de vuelta();
});
}
// Cuando se elimina cualquier objeto con evento, elimina todos sus oyentes.
target.on('dispose', () => {
objetivo.off();
[objetivo, objetivo.el_, objetivo.eventBusEl_].forEach(function(val) {
si (valor && DomData.has(val)) {
DomData.delete(val);
}
});
ventana.setTimeout(() => {
objetivo.eventBusEl_ = nulo;
}, 0);
});
objetivo de retorno;
}
evento predeterminado de exportación;
exportar {isEvented};
exportar {addEventedCallback};