/**
* @archivo plugin.js
* /
importar eventos desde './mixins/evented';
importar con estado desde './mixins/stateful';
importar * como Eventos desde './utils/events';
importar registro desde './utils/log';
importar jugador desde './jugador';
/**
* El nombre del complemento base.
*
* @privado
* @constante
* @tipo {cadena}
* /
const BASE_PLUGIN_NAME = 'complemento';
/**
* La clave en la que se almacena el caché de complementos activos de un jugador.
*
* @privado
* @constante
* @tipo {cadena}
* /
const PLUGIN_CACHE_KEY = 'activePlugins_';
/**
* Almacena complementos registrados en un espacio privado.
*
* @privado
* @type {Objeto}
* /
const pluginStorage = {};
/**
* Informa si se ha registrado o no un complemento.
*
* @privado
* @param {cadena} nombre
* El nombre de un complemento.
*
* @return {booleano}
* Si el complemento se ha registrado o no.
* /
const pluginExists = (nombre) => pluginStorage.hasOwnProperty(nombre);
/**
* Obtenga un solo complemento registrado por nombre.
*
* @privado
* @param {cadena} nombre
* El nombre de un complemento.
*
* @return {Función|indefinido}
* El complemento (o indefinido).
* /
const getPlugin = (nombre) => pluginExiste(nombre) ? pluginStorage[nombre]: indefinido;
/**
* Marca un complemento como "activo" en un reproductor.
*
* Además, asegura que el reproductor tenga un objeto para rastrear complementos activos.
*
* @privado
* @param {Jugador} jugador
* Una instancia del reproductor Video.js.
*
* @param {cadena} nombre
* El nombre de un complemento.
* /
const markPluginAsActive = (jugador, nombre) => {
jugador[PLUGIN_CACHE_KEY] = jugador[PLUGIN_CACHE_KEY] || {};
jugador[PLUGIN_CACHE_KEY][nombre] = verdadero;
};
/**
* Activa un par de eventos de configuración de complementos.
*
* @privado
* @param {Jugador} jugador
* Una instancia del reproductor Video.js.
*
* @param {Plugin~PluginEventHash} hash
* Un hash de evento de complemento.
*
* @param {booleano} [antes]
* Si es verdadero, antecede el nombre del evento con "antes". En otras palabras,
* use esto para activar "beforepluginsetup" en lugar de "pluginsetup".
* /
const triggerSetupEvent = (jugador, hash, antes) => {
const eventName = (antes? 'antes': '') + 'pluginsetup';
player.trigger(nombreEvento, hash);
jugador.trigger(nombreEvento + ':' + hash.nombre, hash);
};
/**
* Toma una función básica de complemento y devuelve una función contenedora que marca
* en el reproductor que se ha activado el complemento.
*
* @privado
* @param {cadena} nombre
* El nombre del complemento.
*
* Complemento @param {Función}
* El complemento básico.
*
* @return {Función}
* Una función contenedora para el complemento dado.
* /
const createBasicPlugin = función (nombre, complemento) {
const basicPluginWrapper = function() {
// Activamos los eventos "beforepluginsetup" y "pluginsetup" en el reproductor
// independientemente, pero queremos que el hash sea coherente con el hash proporcionado
// para complementos avanzados.
//
// Lo único potencialmente contrario a la intuición aquí es la `instancia` en
// el evento "pluginsetup" es el valor devuelto por la función `plugin`.
triggerSetupEvent (esto, {nombre, complemento, instancia: nulo}, verdadero);
const instancia = plugin.apply(esto, argumentos);
markPluginAsActive(esto, nombre);
triggerSetupEvent(este, {nombre, complemento, instancia});
instancia de retorno;
};
Object.keys(complemento).forEach(función(prop) {
basicPluginWrapper[prop] = plugin[prop];
});
volver basicPluginWrapper;
};
/**
* Toma una subclase de complemento y devuelve una función de fábrica para generar
* instancias de la misma.
*
* Esta función de fábrica se reemplazará con una instancia de la solicitada
* subclase de Complemento.
*
* @privado
* @param {cadena} nombre
* El nombre del complemento.
*
* @param {Complemento} Subclase de complemento
* El complemento avanzado.
*
* @return {Función}
* /
const createPluginFactory = (nombre, PluginSubClass) => {
// Agregue una propiedad `nombre` al prototipo del complemento para que cada complemento pueda
// referirse a sí mismo por su nombre.
PluginSubClass.prototype.name = nombre;
función de retorno (... argumentos) {
triggerSetupEvent(este, {nombre, complemento: PluginSubClass, instancia: nulo}, verdadero);
const instancia = nueva PluginSubClass(...[this, ...args]);
// El complemento se reemplaza por una función que devuelve la instancia actual.
este[nombre] = () => instancia;
triggerSetupEvent(esto, instancia.getEventHash());
instancia de retorno;
};
};
/**
* Clase principal para todos los complementos avanzados.
*
* Módulo @mixes:evented~EventedMixin
* Módulo @mixes: stateful~StatefulMixin
* @fires Player#beforepluginsetup
* @fires Player#beforepluginsetup:$nombre
* @fires jugador#pluginsetup
* @fires Player#pluginsetup:$nombre
* @escucha Player#dispose
* @throws {Error}
* Si se intenta crear una instancia de la clase base {@link Plugin}
* directamente en lugar de a través de una subclase.
* /
Complemento de clase {
/**
* Crea una instancia de esta clase.
*
* Las subclases deben llamar a `super` para garantizar que los complementos se inicialicen correctamente.
*
* @param {Jugador} jugador
* Una instancia del reproductor Video.js.
* /
constructor (jugador) {
if (this.constructor === Complemento) {
throw new Error('El complemento debe ser subclasificado; no instanciado directamente.');
}
este.jugador = jugador;
si (!este.registro) {
this.log = this.player.log.createLogger(this.name);
}
// Haga que este objeto sea un evento, pero elimine el método `trigger` agregado para que podamos
// use la versión prototipo en su lugar.
evento(esto);
eliminar este disparador;
stateful(this, this.constructor.defaultState);
markPluginAsActive(jugador, este.nombre);
// Vincular automáticamente el método dispose para que podamos usarlo como oyente y desvincularlo
// más tarde fácilmente.
this.dispose = this.dispose.bind(this);
// Si se desecha el reproductor, desechar el complemento.
player.on('dispose', this.dispose);
}
/**
* Obtenga la versión del complemento que se configuró < pluginName> .VERSIÓN
* /
versión() {
devuelve este.constructor.VERSIÓN;
}
/**
* Cada evento activado por complementos incluye un hash de datos adicionales con
* propiedades convencionales.
*
* Esto devuelve ese objeto o muta un hash existente.
*
* @param {Objeto} [hash={}]
* Un objeto para ser utilizado como evento y hash de evento.
*
* @return {Complemento~PluginEventHash}
* Un objeto hash de evento con las propiedades proporcionadas mezcladas.
* /
getEventHash(hash = {}) {
hash.nombre = este.nombre;
hash.plugin = este.constructor;
hash.instancia = esto;
hash de retorno;
}
/**
* Activa un evento en el objeto del complemento y anula
* {@link module:evented~EventedMixin.trigger|EventedMixin.trigger}.
*
* @param {cadena|Objeto} evento
* Un tipo de evento o un objeto con una propiedad de tipo.
*
* @param {Objeto} [hash={}]
* Hash de datos adicional para fusionar con un
* {Complemento @link~PluginEventHash|PluginEventHash}.
*
* @return {booleano}
* Si se evitó o no el incumplimiento.
* /
disparador (evento, hash = {}) {
return Events.trigger(this.eventBusEl_, event, this.getEventHash(hash));
}
/**
* Maneja eventos de "cambio de estado" en el complemento. No-op por defecto, anular por
* subclasificación.
*
* @abstracto
* @param {Evento} e
* Un objeto de evento proporcionado por un evento de "cambio de estado".
*
* @param {Objeto} e.cambios
* Un objeto que describe los cambios que ocurrieron con el "estado cambiado"
* evento.
* /
manejarEstadoCambiado(e) {}
/**
* Dispone de un complemento.
*
* Las subclases pueden anular esto si quieren, pero por razones de seguridad,
* Probablemente sea mejor suscribirse al evento "dispose".
*
* Complemento @fires#dispose
* /
disponer () {
const {nombre, jugador} = esto;
/**
* Señales de que un complemento avanzado está a punto de ser eliminado.
*
* Complemento @event #dispose
* @type {Objetivo del evento~Evento}
* /
this.trigger('dispose');
esto.off();
player.off('dispose', this.dispose);
// Elimine cualquier posible fuente de pérdida de memoria limpiando
// referencias entre el reproductor y la instancia del complemento y la anulación
// el estado del complemento y los métodos de reemplazo con una función que lanza.
jugador[PLUGIN_CACHE_KEY][nombre] = falso;
este.jugador = este.estado = nulo;
// Finalmente, reemplace el nombre del complemento en el reproductor con una nueva fábrica
// función, para que el complemento esté listo para configurarse nuevamente.
jugador[nombre] = createPluginFactory(nombre, pluginStorage[nombre]);
}
/**
* Determina si un complemento es un complemento básico (es decir, no una subclase de `Plugin`).
*
* complemento @param {cadena|Función}
* Si es una cadena, coincide con el nombre de un complemento. Si una función, será
* probado directamente.
*
* @return {booleano}
* Si un complemento es o no un complemento básico.
* /
isBasic estático (complemento) {
const p = (tipo de complemento === 'cadena') ? getPlugin(complemento): complemento;
tipo de retorno de p === 'función' && !Plugin.prototype.isPrototypeOf(p.prototype);
}
/**
* Registre un complemento Video.js.
*
* @param {cadena} nombre
* El nombre del plugin a registrar. Debe ser una cadena y
* no debe coincidir con un complemento existente o un método en el "Reproductor"
* prototipo.
*
* Complemento @param {Función}
* Una subclase de `Plugin` o una función para complementos básicos.
*
* @return {Función}
* Para complementos avanzados, una función de fábrica para ese complemento. Para
* Complementos básicos, una función contenedora que inicializa el complemento.
* /
static registerPlugin(nombre, complemento) {
if (tipo de nombre !== 'cadena') {
throw new Error(`Nombre de complemento ilegal, "${name}", debe ser una cadena, era ${typeof name}.`);
}
if (el complemento existe (nombre)) {
log.warn(`Ya existe un complemento llamado "${name}". ¡Es posible que desee evitar volver a registrar complementos!`);
} else if (Jugador.prototipo.hasOwnProperty(nombre)) {
throw new Error(`Nombre de complemento ilegal, "${name}", ¡no se puede compartir un nombre con un método de reproductor existente!`);
}
if (tipo de complemento! == 'función') {
throw new Error(`Complemento ilegal para "${name}", debe ser una función, era ${typeof plugin}.`);
}
pluginStorage[nombre] = complemento;
// Agregue un método de prototipo de jugador para todos los complementos subclasificados (pero no para
// la clase de complemento base).
if (nombre !== NOMBRE_PLUGIN_BASE) {
if (Plugin.isBasic(complemento)) {
Player.prototype[nombre] = createBasicPlugin(nombre, complemento);
} else {
Player.prototype[nombre] = createPluginFactory(nombre, complemento);
}
}
complemento de retorno;
}
/**
* Dar de baja un complemento Video.js.
*
* @param {cadena} nombre
* El nombre del complemento que se va a dar de baja. Debe ser una cadena que
* coincide con un complemento existente.
*
* @throws {Error}
* Si se intenta anular el registro del complemento base.
* /
static deregisterPlugin(nombre) {
if (nombre === NOMBRE_PLUGIN_BASE) {
throw new Error('No se puede cancelar el registro del complemento base.');
}
if (el complemento existe (nombre)) {
eliminar pluginStorage[nombre];
eliminar Player.prototype[nombre];
}
}
/**
* Obtiene un objeto que contiene varios complementos de Video.js.
*
* @param {Array} [nombres]
* Si se proporciona, debe ser una matriz de nombres de complementos. El valor predeterminado es _todos_
* nombres de complementos.
*
* @return {Objeto|indefinido}
* Un objeto que contiene complemento(s) asociado(s) con su(s) nombre(s) o
* `undefined` si no existen complementos coincidentes).
* /
getPlugins estáticos (nombres = Object.keys (pluginStorage)) {
deja que resulte;
nombres.paraCada(nombre => {
complemento const = getPlugin(nombre);
si (complemento) {
resultado = resultado || {};
resultado[nombre] = complemento;
}
});
resultado devuelto;
}
/**
* Obtiene la versión de un complemento, si está disponible
*
* @param {cadena} nombre
* El nombre de un complemento.
*
* @return {cadena}
* La versión del complemento o una cadena vacía.
* /
getPluginVersion estática (nombre) {
complemento const = getPlugin(nombre);
complemento de retorno && complemento.VERSIÓN || '';
}
}
/**
* Obtiene un complemento por su nombre si existe.
*
* @estático
* @método getPlugin
* Complemento @memberOf
* @param {cadena} nombre
* El nombre de un complemento.
*
* @returns {Función|indefinido}
* El complemento (o `indefinido`).
* /
Complemento.getPlugin = getPlugin;
/**
* El nombre de la clase de complemento base tal como está registrada.
*
* @tipo {cadena}
* /
Complemento.BASE_PLUGIN_NAME = BASE_PLUGIN_NAME;
Plugin.registerPlugin(BASE_PLUGIN_NAME, Complemento);
/**
* Documentado en player.js
*
* @ignorar
* /
Player.prototype.usingPlugin = función (nombre) {
devolver !!este[PLUGIN_CACHE_KEY] && este[PLUGIN_CACHE_KEY][nombre] === verdadero;
};
/**
* Documentado en player.js
*
* @ignorar
* /
Player.prototype.hasPlugin = función (nombre) {
return !!pluginExists(nombre);
};
Exportar complemento predeterminado;
/**
* Indica que un complemento está a punto de configurarse en un reproductor.
*
* @event Player#beforepluginsetup
* @type {Complemento~PluginEventHash}
* /
/**
* Indica que un complemento está a punto de configurarse en un reproductor, por nombre. El nombre
* es el nombre del complemento.
*
* @event Player#beforepluginsetup:$nombre
* @type {Complemento~PluginEventHash}
* /
/**
* Indica que se acaba de configurar un complemento en un reproductor.
*
* @reproductor de eventos#pluginsetup
* @type {Complemento~PluginEventHash}
* /
/**
* Indica que se acaba de configurar un complemento en un reproductor, por nombre. El nombre
* es el nombre del complemento.
*
* @event Player#pluginsetup:$nombre
* @type {Complemento~PluginEventHash}
* /
/**
* @typedef {Objeto} Complemento ~ PluginEventHash
*
* instancia de @property {cadena}
* Para complementos básicos, el valor de retorno de la función del complemento. Para
* Complementos avanzados, la instancia del complemento en la que se activa el evento.
*
* @propiedad {cadena} nombre
* El nombre del complemento.
*
* Complemento @property {cadena}
* Para complementos básicos, la función de complemento. Para complementos avanzados, el
* Clase de complemento/constructor.
* /