/**
* Componente de reproductor: clase base para todos los objetos de la interfaz de usuario
*
* @archivo componente.js
* /
importar ventana desde 'global/window';
importar eventos desde './mixins/evented';
importar con estado desde './mixins/stateful';
importar * como Dom desde './utils/dom.js';
importar * como Fn desde './utils/fn.js';
importar * como Guid desde './utils/guid.js';
importar {toTitleCase, toLowerCase} desde './utils/string-cases.js';
importar mergeOptions desde './utils/merge-options.js';
importar estilo computado desde './utils/computed-style';
importar mapa desde './utils/map.js';
importar conjunto desde './utils/set.js';
importar código clave desde 'código clave';
/**
* Clase base para todos los componentes de la interfaz de usuario.
* Los componentes son objetos de interfaz de usuario que representan tanto un objeto javascript como un elemento
* en el DOM. Pueden ser hijos de otros componentes y pueden tener
* los propios niños.
*
* Los componentes también pueden usar métodos de {@link EventTarget}
* /
componente de clase {
/**
* Una devolución de llamada que se llama cuando un componente está listo. no tiene ninguna
* Se ignorarán los parámetros y cualquier valor de devolución de llamada.
*
* Componente @callback~ReadyCallback
* @este componente
* /
/**
* Crea una instancia de esta clase.
*
* @param {Jugador} jugador
* El `Jugador` al que se debe adjuntar esta clase.
*
* @param {Objeto} [opciones]
* El almacén de clave/valor de las opciones de componentes.
*
* @param {Objeto[]} [opciones.niños]
* Una matriz de objetos secundarios para inicializar este componente. Los objetos infantiles tienen
* una propiedad de nombre que se usará si se necesita más de un componente del mismo tipo
* agregado.
*
* @param {cadena} [opciones.className]
* Una lista de clases separadas por espacios o clases para agregar el componente
*
* @param {Componente~ReadyCallback} [listo]
* Función que se llama cuando el 'Componente' está listo.
* /
constructor(jugador, opciones, listo) {
// El componente podría ser el propio reproductor y no podemos pasar `this` a super
si (!jugador && este juego) {
este.jugador_ = jugador = esto; // eslint-disable-line
} else {
este.jugador_ = jugador;
}
this.isDisposed_ = false;
// Mantener la referencia al componente principal a través del método `addChild`
this.parentComponent_ = null;
// Haga una copia de prototipo.opciones_ para protegerse contra la anulación de valores predeterminados
this.options_ = mergeOptions({}, this.options_);
// Opciones actualizadas con opciones suministradas
opciones = this.options_ = mergeOptions(this.options_, options);
// Obtener ID de opciones o elemento de opciones si se proporciona uno
this.id_ = opciones.id || (opciones.el && opciones.el.id);
// Si no hubo ID de las opciones, generar uno
si (!este.id_) {
// No requiere la función de ID de jugador en el caso de jugadores ficticios
const id = jugador && jugador.id && jugador.id() || 'no_jugador';
this.id_ = `${id}_component_${Guid.newGUID()}`;
}
this.name_ = opciones.nombre || nulo;
// Crear elemento si no se proporcionó uno en las opciones
if (opciones.el) {
this.el_ = opciones.el;
} else if (opciones.createEl !== falso) {
esto.el_ = esto.createEl();
}
if (opciones.nombreClase && esto.el_) {
options.className.split(' ').forEach(c => esto.addClass(c));
}
// si evented es cualquier cosa menos falso, queremos mezclarlo en evented
if (opciones.evento !== falso) {
// Hacer de este un objeto con eventos y usar `el_`, si está disponible, como su bus de eventos
evented(this, {eventBusKey: this.el_ ? 'el_' : null});
this.handleLanguagechange = this.handleLanguagechange.bind(this);
this.on(this.player_, 'languagechange', this.handleLanguagechange);
}
stateful(this, this.constructor.defaultState);
esto.niños_ = [];
this.childIndex_ = {};
this.childNameIndex_ = {};
this.setTimeoutIds_ = nuevo Conjunto();
this.setIntervalIds_ = nuevo Conjunto();
this.rafIds_ = nuevo Conjunto();
this.namedRafs_ = nuevo Mapa();
this.clearingTimersOnDispose_ = falso;
// Agregue cualquier componente secundario en las opciones
if (opciones.initChildren !== falso) {
esto.initChildren();
}
// No quiero desencadenar listo aquí o irá antes de que init sea realmente
// terminado para todos los niños que ejecutan este constructor
esto.listo(listo);
if (opciones.reportTouchActivity!== false) {
this.enableTouchActivity();
}
}
/**
* Deseche el `Componente` y todos los componentes secundarios.
*
* Componente @fires#dispose
*
* @param {Objeto} opciones
* @param {Element} options.originalEl elemento con el que reemplazar el elemento jugador
* /
disponer(opciones = {}) {
// Rescatar si el componente ya ha sido desechado.
if (this.isDisposed_) {
devolver;
}
if (this.readyQueue_) {
this.readyQueue_.longitud = 0;
}
/**
* Se activa cuando se desecha un 'Componente'.
*
* @event Component#dispose
* @type {Objetivo del evento~Evento}
*
* @propiedad {booleano} [burbujas=falso]
* establecido en falso para que el evento de eliminación no
* burbujear
* /
this.trigger({tipo: 'desechar', burbujas: falso});
this.isDisposed_ = true;
// Deshágase de todos los niños.
si (esto.niños_) {
for (sea i = this.children_.length - 1; i > = 0; i--) {
if (esto.niños_[i].dispose) {
this.children_[i].dispose();
}
}
}
// Eliminar referencias secundarias
esto.niños_ = nulo;
este.childIndex_ = nulo;
this.childNameIndex_ = nulo;
this.parentComponent_ = null;
si (esto.el_) {
// Eliminar elemento de DOM
if (this.el_.parentNode) {
if (opciones.restoreEl) {
this.el_.parentNode.replaceChild(options.restoreEl, this.el_);
} else {
this.el_.parentNode.removeChild(this.el_);
}
}
esto.el_ = nulo;
}
// elimina la referencia al jugador después de deshacerse del elemento
este.jugador_ = nulo;
}
/**
* Determinar si este componente ha sido desechado o no.
*
* @return {booleano}
* Si el componente ha sido desechado, será `verdadero`. De lo contrario, `falso`.
* /
se desecha() {
return Boolean(this.isDisposed_);
}
/**
* Devolver el {@link Player} al que se adjuntó el `Componente`.
*
* @return {Jugador}
* El jugador al que se ha adjuntado este `Componente`.
* /
jugador() {
devolver este.jugador_;
}
/**
* Fusión profunda de objetos de opciones con nuevas opciones.
* > Nota: Cuando tanto `obj` como `options` contienen propiedades cuyos valores son objetos.
* Las dos propiedades se fusionan usando {@link module:mergeOptions}
*
* @param {Objeto} obj
* El objeto que contiene nuevas opciones.
*
* @return {Objeto}
* Un nuevo objeto de `this.options_` y `obj` se fusionaron.
* /
opciones (obj) {
si (! objeto) {
devuelve esto.opciones_;
}
this.options_ = mergeOptions(this.options_, obj);
devuelve esto.opciones_;
}
/**
* Obtener el elemento DOM del 'Componente'
*
* @return {Elemento}
* El elemento DOM para este `Componente`.
* /
el() {
devolver esto.el_;
}
/**
* Crear el elemento DOM `Component`.
*
* @param {cadena} [nombre de etiqueta]
* Tipo de nodo DOM del elemento. por ejemplo, 'div'
*
* @param {Objeto} [propiedades]
* Un objeto de propiedades que debe establecerse.
*
* @param {Objeto} [atributos]
* Un objeto de atributos que debe establecerse.
*
* @return {Elemento}
* El elemento que se crea.
* /
createEl(tagName, propiedades, atributos) {
return Dom.createEl(tagName, propiedades, atributos);
}
/**
* Localizar una cadena dada la cadena en inglés.
*
* Si se proporcionan tokens, intentará ejecutar un reemplazo de token simple en la cadena proporcionada.
* Los tokens que busca se parecen a `{1}` con el índice indexado en 1 en la matriz de tokens.
*
* Si se proporciona un `defaultValue`, lo usará sobre `string`,
* si no se encuentra un valor en los archivos de idioma proporcionados.
* Esto es útil si desea tener una clave descriptiva para el reemplazo de tokens
* pero tiene una cadena localizada sucinta y no requiere que se incluya `en.json`.
*
* Actualmente, se utiliza para el tiempo de la barra de progreso.
* ```js
* {
* "tiempo de la barra de progreso: hora actual = {1} duración = {2}": "{1} de {2}"
* }
* ```
* Entonces se usa así:
* ```js
* this.localize('tiempo de la barra de progreso: horaActual={1} duración{2}',
* [este.jugador_.tiempoActual(), este.jugador_.duración()],
* '{1 de 2}');
* ```
*
* Lo que genera algo como: `01:23 de 24:56`.
*
*
* @param {cadena} cadena
* La cadena para localizar y la clave para buscar en los archivos de idioma.
* @param {cadena[]} [tokens]
* Si el elemento actual tiene reemplazos de fichas, proporcione las fichas aquí.
* @param {cadena} [valor predeterminado]
* Por defecto es `cadena`. Puede ser un valor predeterminado para usar para el reemplazo del token
* si la clave de búsqueda debe estar separada.
*
* @return {cadena}
* La cadena localizada o, si no existe localización, la cadena en inglés.
* /
localizar (cadena, tokens, valor predeterminado = cadena) {
código constante = this.player_.language && este.jugador_.idioma();
const idiomas = this.player_.languages && este.jugador_.idiomas();
const idioma = idiomas && idiomas[código];
const códigoprimario = código && código.split('-')[0];
const PrimaryLang = idiomas && idiomas[primaryCode];
let localizadoString = defaultValue;
si (idioma && idioma[cadena]) {
cadenaLocalizada = idioma[cadena];
} más si (primaryLang && idiomaprimario[cadena]) {
cadenaLocalizada = idiomaPrincipal[cadena];
}
si (fichas) {
cadenaLocalizada = CadenaLocalizada.replace(/\{(\d+)\}/g, función(coincidencia, índice) {
valor const = fichas [índice - 1];
sea ret = valor;
if (tipo de valor === 'indefinido') {
ret = partido;
}
volver ret;
});
}
return cadena localizada;
}
/**
* Maneja el cambio de idioma para el jugador en componentes. Debe ser anulado por subcomponentes.
*
* @abstracto
* /
manejarcambioIdioma() {}
/**
* Devuelve el elemento DOM del 'Componente'. Aquí es donde se insertan los niños.
* Por lo general, será el mismo que el elemento devuelto en {@link Component#el}.
*
* @return {Elemento}
* El elemento de contenido para este `Componente`.
* /
contenidoEl() {
devolver este.contentEl_ || esto.el_;
}
/**
* Obtener el ID de este 'Componente'
*
* @return {cadena}
* El id de este `Componente`
* /
identificación() {
devolver este.id_;
}
/**
* Obtener el nombre del 'Componente'. El nombre se usa para hacer referencia al `Componente`
* y se establece durante el registro.
*
* @return {cadena}
* El nombre de este `Componente`.
* /
nombre() {
devuelve este.nombre_;
}
/**
* Obtenga una matriz de todos los componentes secundarios
*
* @return {Array}
* Los niños
* /
niños() {
devolver esto.niños_;
}
/**
* Devuelve el 'Componente' secundario con el 'id' dado.
*
* @param {cadena} id
* La identificación del 'Componente' secundario que se va a obtener.
*
* @return {Componente|indefinido}
* El 'Componente' secundario con el 'id' dado o indefinido.
* /
getChildById(id) {
devolver esto.childIndex_[id];
}
/**
* Devuelve el 'Componente' secundario con el 'nombre' dado.
*
* @param {cadena} nombre
* El nombre del 'Componente' secundario que se va a obtener.
*
* @return {Componente|indefinido}
* El 'Componente' secundario con el 'nombre' dado o indefinido.
* /
getChild(nombre) {
si (! nombre) {
devolver;
}
devuelve this.childNameIndex_[nombre];
}
/**
* Devuelve el 'Componente' descendiente que sigue al dado
* `nombres` descendientes. Por ejemplo ['foo', 'bar', 'baz'] sería
* intente obtener 'foo' en el componente actual, 'bar' en 'foo'
* componente y 'baz' en el componente 'barra' y devuelve indefinido
* si alguno de esos no existe.
*
* @param {...cadena[]|...cadena} nombres
* El nombre del 'Componente' secundario que se va a obtener.
*
* @return {Componente|indefinido}
* El 'Componente' descendiente que sigue al descendiente dado
* `nombres` o indefinido.
* /
getDescendiente(...nombres) {
// aplana el argumento de la matriz en la matriz principal
nombres = nombres.reduce((acc, n) => acc.concat(n), []);
let currentChild = esto;
para (sea i = 0; i < nombres.longitud; i++) {
hijoActual = HijoActual.getChild(nombres[i]);
if (!niñoactual || !niñoactual.getChild) {
devolver;
}
}
volver hijo actual;
}
/**
* Agregue un 'Componente' secundario dentro del 'Componente' actual.
*
*
* @param {cadena|Componente} niño
* El nombre o instancia de un niño para agregar.
*
* @param {Objeto} [opciones={}]
* El almacén de claves/valores de opciones que se pasarán a los hijos de
* el niño.
*
* @param {número} [índice=este.niños_.longitud]
* El índice para intentar agregar un niño.
*
* @return {Componente}
* El `Componente` que se agrega como hijo. Cuando se usa una cuerda, el
* `Componente` será creado por este proceso.
* /
addChild(child, options = {}, index = this.children_.length) {
dejar componente;
let nombreComponente;
// Si el hijo es una cadena, crea un componente con opciones
if (tipo de niño === 'cadena') {
nombreComponente = toTitleCase(hijo);
const nombreClaseComponente = opciones.claseComponente || Nombre del componente;
// Establecer nombre a través de opciones
opciones.nombre = nombreComponente;
// Crea un nuevo objeto & elemento para este conjunto de controles
// Si no hay .player_, este es un jugador
const ComponentClass = Component.getComponent(componentClassName);
if (!ClaseComponente) {
throw new Error(`El componente ${componentClassName} no existe`);
}
// los datos almacenados directamente en el objeto videojs pueden ser
// identificado erróneamente como un componente para retener
// compatibilidad hacia atrás con 4.x. verifique para asegurarse de que
// la clase de componente puede ser instanciada.
if (tipo de clase de componente! == 'función') {
devolver nulo;
}
componente = new ComponentClass(this.player_ || this, options);
// hijo es una instancia de componente
} else {
componente = hijo;
}
si (componente.parentComponent_) {
componente.parentComponent_.removeChild(componente);
}
this.children_.splice(índice, 0, componente);
componente.parentComponent_ = esto;
if (tipo de componente.id === 'función') {
this.childIndex_[componente.id()] = componente;
}
// Si no se usó un nombre para crear el componente, verifique si podemos usar el
// función de nombre del componente
nombre del componente = nombre del componente || (Nombre del componente && toTitleCase(componente.nombre()));
si (nombre del componente) {
this.childNameIndex_[componentName] = componente;
this.childNameIndex_[toLowerCase(componentName)] = componente;
}
// Agregue el elemento del objeto de la interfaz de usuario al contenedor div (caja)
// No es necesario tener un elemento
if (tipodecomponente.el === 'función' && componente.el()) {
// Si inserta antes de un componente, inserte antes del elemento de ese componente
let refNode = nulo;
if (esto.niños_[índice + 1]) {
// La mayoría de los niños son componentes, pero la tecnología de video es un elemento HTML
if (esto.niños_[índice + 1].el_) {
refNode = this.children_[índice + 1].el_;
} else if (Dom.isEl(this.children_[index + 1])) {
refNode = this.children_[índice + 1];
}
}
this.contentEl().insertBefore(component.el(), refNode);
}
// Regrese para que pueda almacenarse en el objeto principal si lo desea.
componente de retorno;
}
/**
* Eliminar un 'Componente' secundario de la lista de elementos secundarios de este 'Componente'. también elimina
* el elemento `Component` secundario de este elemento `Component`.
*
* @param {Componente} componente
* El `Componente` hijo a eliminar.
* /
removeChild(componente) {
if (tipo de componente === 'cadena') {
componente = this.getChild(componente);
}
if (!componente || !este.niños_) {
devolver;
}
let childFound = falso;
for (sea i = this.children_.length - 1; i > = 0; i--) {
if (este.niños_[i] === componente) {
niñoEncontrado = verdadero;
esto.niños_.empalme(i, 1);
romper;
}
}
if (!niñoEncontrado) {
devolver;
}
componente.parentComponent_ = nulo;
this.childIndex_[componente.id()] = nulo;
this.childNameIndex_[toTitleCase(component.name())] = null;
this.childNameIndex_[toLowerCase(component.name())] = null;
const compEl = componente.el();
si (compEl && compEl.parentNode === this.contentEl()) {
this.contentEl().removeChild(componente.el());
}
}
/**
* Agregue e inicialice los 'Componentes' secundarios predeterminados en función de las opciones.
* /
initChildren() {
const niños = esto.opciones_.niños;
si (hijos) {
// `este` es `padre`
const parentOptions = this.options_;
const handleAdd = (hijo) => {
const nombre = hijo.nombre;
let opts = child.opts;
// Permitir que las opciones para los hijos se establezcan en las opciones de los padres
// por ejemplo, videojs(id, { barra de control: falso });
// en lugar de videojs(id, { children: { controlBar: false });
if (parentOptions[nombre] !== indefinido) {
opciones = parentOptions[nombre];
}
// Permitir la desactivación de componentes predeterminados
// por ejemplo, options['child']['posterImage'] = false
si (opta === falso) {
devolver;
}
// Permitir que las opciones se pasen como un booleano simple si no hay configuración
// es necesario.
if (opta === verdadero) {
opciones = {};
}
// También queremos pasar las opciones del jugador original
// a cada componente también para que no necesiten
// Vuelva a buscar opciones en el reproductor más adelante.
opts.playerOptions = this.options_.playerOptions;
// Crear y agregar el componente secundario.
// Agregue una referencia directa al hijo por nombre en la instancia principal.
// Si se utilizan dos del mismo componente, se deben proporcionar nombres diferentes
// para cada
const newChild = this.addChild(nombre, opciones);
si (nuevoNiño) {
este[nombre] = nuevoNiño;
}
};
// Permitir que se pase una serie de detalles secundarios en las opciones
dejar trabajar a los niños;
const Tecnología = Componente.getComponent('Tecnología');
if (Array.isArray(hijos)) {
niñostrabajadores = niños;
} else {
niñostrabajando = Object.keys(niños);
}
niños trabajando
// los niños que están en this.options_ pero también en workingChildren serían
// danos hijos extra que no queremos. Entonces, queremos filtrarlos.
.concat(Objeto.claves(this.options_)
.filter(función(hijo) {
return !workingChildren.some(function(wchild) {
if (tipo de wchild === 'cadena') {
volver niño === niño;
}
return child === wchild.nombre;
});
}))
.mapa((niño) => {
dejar nombre;
deja que opte;
if (tipo de niño === 'cadena') {
nombre = niño;
opciones = hijos[nombre] || this.options_[nombre] || {};
} else {
nombre = hijo.nombre;
opta = niño;
}
volver {nombre, opciones};
})
.filter((hijo) => {
// tenemos que asegurarnos de que child.name no esté en techOrder ya que
// las tecnologías están registradas como componentes pero no pueden no ser compatibles
// Ver https://github.com/videojs/video.js/issues/2772
const c = Componente.getComponent(child.opts.componentClass ||
toTitleCase(niño.nombre));
volver c && !Tecnología.esTecnología(c);
})
.forEach(manejarAñadir);
}
}
/**
* Construye el nombre de clase DOM predeterminado. Debe ser anulado por subcomponentes.
*
* @return {cadena}
* El nombre de la clase DOM para este objeto.
*
* @abstracto
* /
construirClaseCSS() {
// Las clases secundarias pueden incluir una función que hace:
// devuelve 'NOMBRE DE LA CLASE' + this._super();
devolver '';
}
/**
* Vincular un oyente al estado listo del componente.
* Diferente de los oyentes de eventos en que si el evento listo ya sucedió
* activará la función inmediatamente.
*
* @return {Componente}
* Se devuelve a sí mismo; El método se puede encadenar.
* /
listo (fn, sincronizar = falso) {
si (!fn) {
devolver;
}
si (!esto.estáListo_) {
this.readyQueue_ = this.readyQueue_ || [];
this.readyQueue_.push(fn);
devolver;
}
si (sincronizar) {
fn.llamar(esto);
} else {
// Llamar a la función de forma asíncrona por defecto para mantener la coherencia
esto.setTimeout(fn, 1);
}
}
/**
* Active todos los oyentes listos para este 'Componente'.
*
* @fires Componente#listo
* /
activadorListo() {
esto.estáListo_ = verdadero;
// Asegurarse de que ready se active de forma asíncrona
this.setTimeout(función() {
const readyQueue = this.readyQueue_;
// Restablecer la cola de listos
this.readyQueue_ = [];
si (cola lista && readyQueue.longitud > 0) {
readyQueue.forEach(función(fn) {
fn.llamar(esto);
}, this);
}
// Permitir el uso de detectores de eventos también
/**
* Activado cuando un 'Componente' está listo.
*
* @event Componente#listo
* @type {Objetivo del evento~Evento}
* /
this.trigger('listo');
}, 1);
}
/**
* Encuentra un solo elemento DOM que coincida con un `selector`. Esto puede estar dentro del `Component`s
* `contentEl()` u otro contexto personalizado.
*
* Selector @param {cadena}
* Un selector de CSS válido, que se pasará a `querySelector`.
*
* @param {Elemento|cadena} [contexto=este.contentEl()]
* Un elemento DOM dentro del cual consultar. También puede ser una cadena selectora en
* en cuyo caso el primer elemento coincidente se usará como contexto. Si
* falta `this.contentEl()` se usa. Si `this.contentEl()` regresa
* nada, vuelve a `document`.
*
* @return {Elemento|null}
* el elemento dom que se encontró, o nulo
*
* @ver [Información sobre los selectores de CSS](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
* /
$(selector, contexto) {
return Dom.$(selector, contexto || this.contentEl());
}
/**
* Encuentra todos los elementos DOM que coincidan con un `selector`. Esto puede estar dentro del `Component`s
* `contentEl()` u otro contexto personalizado.
*
* Selector @param {cadena}
* Un selector de CSS válido, que se pasará a `querySelectorAll`.
*
* @param {Elemento|cadena} [contexto=este.contentEl()]
* Un elemento DOM dentro del cual consultar. También puede ser una cadena selectora en
* en cuyo caso el primer elemento coincidente se usará como contexto. Si
* falta `this.contentEl()` se usa. Si `this.contentEl()` regresa
* nada, vuelve a `document`.
*
* @return {Lista de nodos}
* una lista de elementos dom que se encontraron
*
* @ver [Información sobre los selectores de CSS](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_Started/Selectors)
* /
$$(selector, contexto) {
return Dom.$$(selector, contexto || this.contentEl());
}
/**
* Comprobar si el elemento de un componente tiene un nombre de clase CSS.
*
* @param {cadena} classToCheck
* Nombre de la clase CSS para comprobar.
*
* @return {booleano}
* - Verdadero si el `Componente` tiene la clase.
* - Falso si el `Componente` no tiene la clase`
* /
tieneClase(claseParaComprobar) {
return Dom.hasClass(this.el_, classToCheck);
}
/**
* Agregue un nombre de clase CSS al elemento `Component`.
*
* @param {cadena} classToAdd
* Nombre de clase CSS para agregar
* /
addClass(classToAdd) {
Dom.addClass(this.el_, classToAdd);
}
/**
* Eliminar un nombre de clase CSS del elemento `Component`.
*
* @param {cadena} classToRemove
* Nombre de clase CSS para eliminar
* /
removeClass(classToRemove) {
Dom.removeClass(this.el_, classToRemove);
}
/**
* Agregue o elimine un nombre de clase CSS del elemento del componente.
* - `classToToggle` se agrega cuando {@link Component#hasClass} devuelve falso.
* - `classToToggle` se elimina cuando {@link Component#hasClass} devuelve verdadero.
*
* @param {cadena} classToToggle
* La clase para agregar o quitar según (@link Component#hasClass}
*
* @param {booleano|Dom~predicado} [predicado]
* Una función {@link Dom~predicate} o un booleano
* /
toggleClass(classToToggle, predicado) {
Dom.toggleClass(this.el_, classToToggle, predicado);
}
/**
* Muestre el elemento `Component` si está oculto eliminando el
* Nombre de clase 'vjs-hidden'.
* /
espectáculo() {
this.removeClass('vjs-hidden');
}
/**
* Oculte el elemento `Component` si se muestra actualmente agregando el
* Nombre de clase 'vjs-hidden`.
* /
esconder() {
this.addClass('vjs-hidden');
}
/**
* Bloquee un elemento `Component`s en su estado visible agregando 'vjs-lock-showing'
* nombre de la clase. Se utiliza durante el fundido de entrada/salida.
*
* @privado
* /
bloqueoMostrando() {
this.addClass('vjs-lock-showing');
}
/**
* Desbloquee un elemento `Component`s de su estado visible eliminando el 'vjs-lock-showing'
* nombre de clase de él. Se utiliza durante el fundido de entrada/salida.
*
* @privado
* /
desbloquearMostrar() {
this.removeClass('vjs-lock-showing');
}
/**
* Obtener el valor de un atributo en el elemento `Component`.
*
* atributo @param {cadena}
* Nombre del atributo del que obtener el valor.
*
* @return {cadena|null}
* - El valor del atributo que se solicitó.
* - Puede ser una cadena vacía en algunos navegadores si el atributo no existe
* o no tiene valor
* - La mayoría de los navegadores devolverán un valor nulo si el atributo no existe o tiene
* sin valor.
*
* @ver [API DOM]{@enlace https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute}
* /
getAttribute(atributo) {
return Dom.getAttribute(this.el_, atributo);
}
/**
* Establecer el valor de un atributo en el elemento `Componente`
*
* atributo @param {cadena}
* Nombre del atributo a configurar.
*
* @param {cadena} valor
* Valor para establecer el atributo.
*
* @ver [API DOM]{@enlace https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute}
* /
setAttribute(atributo, valor) {
Dom.setAttribute(this.el_, atributo, valor);
}
/**
* Eliminar un atributo del elemento `Component`.
*
* atributo @param {cadena}
* Nombre del atributo a eliminar.
*
* @ver [API DOM]{@enlace https://developer.mozilla.org/en-US/docs/Web/API/Element/removeAttribute}
* /
removeAttribute(atributo) {
Dom.removeAttribute(this.el_, atributo);
}
/**
* Obtener o establecer el ancho del componente según los estilos CSS.
* Consulte {@link Component#dimension} para obtener información más detallada.
*
* @param {número|cadena} [número]
* El ancho que desea establecer postfijo con '%', 'px' o nada.
*
* @param {booleano} [skipListeners]
* Omitir el activador de evento de cambio de tamaño de componente
*
* @return {número|cadena}
* El ancho al llegar, cero si no hay ancho. Puede ser una cuerda
* pospixelado con '%' o 'px'.
* /
ancho (num, skipListeners) {
return this.dimension('ancho', num, skipListeners);
}
/**
* Obtenga o establezca la altura del componente en función de los estilos CSS.
* Consulte {@link Component#dimension} para obtener información más detallada.
*
* @param {número|cadena} [número]
* La altura que desea establecer con el postfijo '%', 'px' o nada.
*
* @param {booleano} [skipListeners]
* Omitir el activador de evento de cambio de tamaño de componente
*
* @return {número|cadena}
* El ancho al llegar, cero si no hay ancho. Puede ser una cuerda
* pospixelado con '%' o 'px'.
* /
altura(num, skipListeners) {
return this.dimension('altura', num, skipListeners);
}
/**
* Establecer tanto el ancho como la altura del elemento `Componente` al mismo tiempo.
*
* @param {número|cadena} ancho
* Ancho para establecer el elemento `Component`.
*
* @param {número|cadena} altura
* Altura para establecer el elemento `Component`.
* /
dimensiones (ancho, alto) {
// Omita los oyentes de cambio de tamaño de componente en el ancho para la optimización
this.width(ancho, verdadero);
esta.altura(altura);
}
/**
* Obtener o establecer el ancho o alto del elemento `Componente`. Este es el código compartido.
* para {@link Component#width} y {@link Component#height}.
*
* Cosas que saber:
* - Si el ancho o alto en un número, esto devolverá el número con el postfijo 'px'.
* - Si el ancho/alto es un porcentaje, devolverá el porcentaje con el postfijo '%'
* - Los elementos ocultos tienen un ancho de 0 con `window.getComputedStyle`. Esta función
* por defecto es `style.width` del `Component` y vuelve a `window.getComputedStyle`.
* Ver [este]{@enlace http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/}
* para más información
* - Si desea el estilo calculado del componente, use {@link Component#currentWidth}
* y {@link {Component#currentHeight}
*
* @fires Componente#redimensionarcomponente
*
* @param {cadena} ancho o alto
8 'ancho' o 'alto'
*
* @param {número|cadena} [número]
8 Nueva dimensión
*
* @param {booleano} [skipListeners]
* Omitir desencadenador de evento de cambio de tamaño de componente
*
* @return {número}
* La dimensión al obtener o 0 si no se establece
* /
dimensión (ancho o alto, número, skipListeners) {
if (num !== indefinido) {
// Establecer en cero si es nulo o literalmente NaN (NaN !== NaN)
if (num === nulo || numero !== numero) {
número = 0;
}
// Comprueba si usas ancho/alto css (% o px) y ajusta
if (('' + número).indexOf('%') !== -1 || ('' + número).indexOf('px') !== -1) {
this.el_.style[anchoOAlto] = num;
} else if (num === 'auto') {
this.el_.style[anchoOAlto] = '';
} else {
this.el_.style[anchoOAlto] = num + 'px';
}
// skipListeners nos permite evitar activar el evento de cambio de tamaño al establecer tanto el ancho como el alto
if (!skipOyentes) {
/**
* Se activa cuando se cambia el tamaño de un componente.
*
* @event Componente#redimensionarcomponente
* @type {Objetivo del evento~Evento}
* /
this.trigger('componentresize');
}
devolver;
}
// No establecer un valor, así que obtenerlo
// Asegurarse de que el elemento existe
si (!esto.el_) {
devolver 0;
}
// Obtener el valor de la dimensión del estilo
const val = this.el_.style[anchoOAlto];
const pxIndex = val.indexOf('px');
si (índicepx! == -1) {
// Devuelve el valor del píxel sin 'px'
return parseInt(val.slice(0, pxIndex), 10);
}
// Sin px, por lo que se configuró el uso de % o ningún estilo, por lo que se recurrió a offsetWidth/height
// Si el componente tiene visualización: ninguna, el desplazamiento devolverá 0
// TODO: manejar la visualización: ninguno y ningún estilo de dimensión usando px
return parseInt(this.el_['offset' + toTitleCase(ancho o alto)], 10);
}
/**
* Obtenga el ancho calculado o la altura del elemento del componente.
*
* Usa `window.getComputedStyle`.
*
* @param {cadena} ancho o alto
* Una cadena que contiene 'ancho' o 'alto'. Cualquiera que quieras conseguir.
*
* @return {número}
* La dimensión que se solicita o 0 si no se configuró nada
* para esa dimensión.
* /
dimensión actual (ancho o alto) {
deje calculadoWidthOrHeight = 0;
if (anchoOAlto !== 'ancho' && ancho o alto !== 'alto') {
throw new Error('currentDimension solo acepta valores de ancho o alto');
}
ancho o alto calculado = estilo calculado (this.el_, ancho o alto);
// eliminar 'px' de la variable y analizar como entero
ancho o alto calculado = parseFloat (ancho o alto calculado);
// si el valor calculado sigue siendo 0, es posible que el navegador esté mintiendo
// y queremos verificar los valores de compensación.
// Este código también se ejecuta donde no existe getComputedStyle.
if (anchura o altura calculada === 0 || isNaN(anchura o altura calculada)) {
const rule = `offset${toTitleCase(ancho o alto)}`;
ancho o alto calculado = this.el_[regla];
}
volver ancho o alto calculado;
}
/**
* Un objeto que contiene valores de ancho y alto de los 'Componentes'
* estilo calculado. Utiliza `window.getComputedStyle`.
*
* @typedef {Objeto} Componente ~ DimensionObject
*
* @property {número} ancho
* El ancho del estilo calculado del 'Componente'.
*
* @propiedad {número} altura
* La altura del estilo calculado del 'Componente'.
* /
/**
* Obtenga un objeto que contenga valores calculados de ancho y alto del
* elemento del componente.
*
* Usa `window.getComputedStyle`.
*
* @return {Componente~ObjetoDimensión}
* Las dimensiones calculadas del elemento del componente.
* /
dimensionesactuales() {
regreso {
ancho: this.currentDimension('ancho'),
altura: this.currentDimension('altura')
};
}
/**
* Obtenga el ancho calculado del elemento del componente.
*
* Usa `window.getComputedStyle`.
*
* @return {número}
* El ancho calculado del elemento del componente.
* /
anchoActual() {
devuelve this.currentDimension('ancho');
}
/**
* Obtener la altura calculada del elemento del componente.
*
* Usa `window.getComputedStyle`.
*
* @return {número}
* La altura calculada del elemento del componente.
* /
altura actual() {
devuelve this.currentDimension('altura');
}
/**
* Establecer el foco en este componente
* /
enfocar() {
this.el_.focus();
}
/**
* Eliminar el foco de este componente
* /
difuminar() {
this.el_.blur();
}
/**
* Cuando este Componente recibe un evento `keydown` que no procesa,
* pasa el evento al jugador para su manejo.
*
* @param {EventTarget~Evento} evento
* El evento `keydown` que hizo que se llamara a esta función.
* /
handleKeyDown(evento) {
si (este.jugador_) {
// Solo detenemos la propagación aquí porque queremos que caigan los eventos no controlados
// de vuelta al navegador. Excluir pestaña para reventado de foco.
if (!keycode.isEventKey(evento, 'Tab')) {
event.stopPropagation();
}
this.player_.handleKeyDown(evento);
}
}
/**
* Muchos componentes solían tener un método `handleKeyPress`, que no funcionaba bien.
* nombrado porque escuchó un evento `keydown`. Este nombre de método ahora
* delegados a `handleKeyDown`. Esto significa que cualquiera que llame `handleKeyPress`
* no verá que sus llamadas a métodos dejen de funcionar.
*
* @param {EventTarget~Evento} evento
* El evento que provocó la llamada de esta función.
* /
handleKeyPress(evento) {
this.handleKeyDown(evento);
}
/**
* Emite eventos de 'toque' cuando se detecta soporte de eventos táctiles. esto se acostumbra
* Admite alternar los controles a través de un toque en el video. se habilitan
* porque, de lo contrario, cada subcomponente tendría una sobrecarga adicional.
*
* @privado
* @fires Componente#tap
* @escucha Componente#touchstart
* @escucha Componente#touchmove
* @escucha Componente#touchleave
* @escucha Componente#touchcancel
* @escucha Componente#touchend
* /
emitTapEvents() {
// Seguimiento de la hora de inicio para que podamos determinar cuánto duró el toque
let touchStart = 0;
let firstTouch = nulo;
// El movimiento máximo permitido durante un evento táctil aún se considera un toque
// Otras bibliotecas populares usan desde 2 (hammer.js) hasta 15,
// así que 10 parece un buen número redondo.
const tapMovementThreshold = 10;
// La duración máxima que puede tener un toque sin dejar de ser considerado un toque
const touchTimeThreshold = 200;
vamos podríaBeTap;
this.on('touchstart', function(evento) {
// Si hay más de un dedo, no considere tratar esto como un clic
if (evento.toques.longitud === 1) {
// Copia páginaX/páginaY del objeto
primer toque = {
páginaX: evento.toca[0].páginaX,
páginaY: evento.toca[0].páginaY
};
// Registrar la hora de inicio para que podamos detectar un toque frente a "tocar y mantener"
touchStart = ventana.rendimiento.ahora();
// Restablecer el seguimiento de couldBeTap
podríaBeTap = verdadero;
}
});
this.on('touchmove', function(evento) {
// Si hay más de un dedo, no considere tratar esto como un clic
if (evento.toca.longitud > 1) {
podríaBeTap = false;
} más si (primer Toque) {
// Algunos dispositivos lanzarán movimientos táctiles para todos, excepto para los toques más leves.
// Entonces, si nos moviéramos solo una pequeña distancia, esto aún podría ser un toque
const xdiff = event.touches[0].pageX - firstTouch.pageX;
const ydiff = event.touches[0].pageY - firstTouch.pageY;
const touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
si (distancia táctil > tapMovementThreshold) {
podríaBeTap = false;
}
}
});
const noTap = función () {
podríaBeTap = false;
};
// HACER: Escuche el objetivo original. http://youtu.be/DujfpXOKUp8?t=13m8s
this.on('touchleave', noTap);
this.on('touchcancel', noTap);
// Cuando termine el toque, mida cuánto tiempo tomó y active el apropiado
// evento
this.on('touchend', función(evento) {
primerToque = nulo;
// Continúe solo si el evento touchmove/leave/cancel no sucedió
if (podríaBeTap === verdadero) {
// Mide cuánto duró el toque
const touchTime = ventana.rendimiento.ahora() - touchStart;
// Asegúrese de que el toque fue menor que el umbral para ser considerado un toque
si (tiempo de toque < umbral de tiempo táctil) {
// No permita que el navegador convierta esto en un clic
event.preventDefault();
/**
* Se activa cuando se toca un `Componente`.
*
* @componente del evento#tap
* @type {Objetivo del evento~Evento}
* /
this.trigger('tocar');
// Puede ser bueno copiar el objeto del evento touchend y cambiar el
// escriba para tocar, si las otras propiedades del evento no son exactas después
// Eventos.fixEvent se ejecuta (por ejemplo, event.target)
}
}
});
}
/**
* Esta función informa la actividad del usuario cada vez que ocurren eventos táctiles. esto puede conseguir
* desactivado por cualquier subcomponente que quiera que los eventos táctiles actúen de otra manera.
*
* Informar sobre la actividad táctil del usuario cuando se produzcan eventos táctiles. La actividad del usuario se acostumbra
* determinar cuándo deben mostrarse/ocultarse los controles. Es simple cuando se trata de mouse
* eventos, porque cualquier evento del mouse debería mostrar los controles. Así que capturamos el ratón.
* Eventos que surgen al jugador e informan actividad cuando eso sucede.
* Con eventos táctiles no es tan fácil como `touchstart` y `touchend` toggle player
* control S. Así que los eventos táctiles tampoco nos pueden ayudar a nivel de jugador.
*
* La actividad del usuario se comprueba de forma asíncrona. Entonces, lo que podría pasar es un evento de toque
* en el video apaga los controles. Luego, el evento `touchend` se dispara hasta
* el jugador. Que, si informara sobre la actividad del usuario, cambiaría los controles a la derecha
* de nuevo en. Tampoco queremos bloquear por completo los eventos táctiles para evitar que se burbujeen.
* Además, un evento `touchmove` y cualquier cosa que no sea un toque, no debe activarse
* controles de nuevo en.
*
* @escucha Componente#touchstart
* @escucha Componente#touchmove
* @escucha Componente#touchend
* @escucha Componente#touchcancel
* /
enableTouchActivity() {
// No continúe si el reproductor raíz no admite informar la actividad del usuario
if (!este.jugador() || !este.jugador().reportUserActivity) {
devolver;
}
// oyente para informar que el usuario está activo
informe const = Fn.bind(this.player(), this.player().reportUserActivity);
dejar tocarSostener;
this.on('touchstart', function() {
informe();
// Mientras estén tocando el dispositivo o tengan el mouse presionado,
// los consideramos activos incluso si no mueven el dedo o el mouse.
// Entonces queremos continuar actualizando que están activos
this.clearInterval(touchHolding);
// informe en el mismo intervalo que el control de actividad
touchHolding = this.setInterval(informe, 250);
});
const touchEnd = función (evento) {
informe();
// detener el intervalo que mantiene la actividad si el toque se mantiene
this.clearInterval(touchHolding);
};
this.on('touchmove', informe);
this.on('touchend', touchEnd);
this.on('touchcancel', touchEnd);
}
/**
* Una devolución de llamada que no tiene parámetros y está vinculada al contexto `Component`.
*
* Componente @callback~GenericCallback
* @este componente
* /
/**
* Crea una función que se ejecuta después de un tiempo de espera de `x` milisegundos. Esta función es una
* envoltorio alrededor de `window.setTimeout`. Hay algunas razones para usar este
* en cambio, sin embargo:
* 1. Se borra a través de {@link Component#clearTimeout} cuando
* Se llama a {@link Component#dispose}.
* 2. La devolución de llamada de la función se convertirá en un {@link Component~GenericCallback}
*
* > Nota: No puede usar `window.clearTimeout` en la identificación devuelta por esta función. Esto
* ¡hará que su detector de eliminación no se limpie! Por favor use
* {@link Component#clearTimeout} o {@link Component#dispose} en su lugar.
*
* @param {Componente~GenericCallback} fn
* La función que se ejecutará después de `timeout`.
*
* @param {número} tiempo de espera
* Tiempo de espera en milisegundos para demorar antes de ejecutar la función especificada.
*
* @return {número}
* Devuelve una ID de tiempo de espera que se usa para identificar el tiempo de espera. También puede
* se usa en {@link Component#clearTimeout} para borrar el tiempo de espera que
* se estableció.
*
* @escucha Componente#dispose
* @ver [Similar a]{@enlace https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout}
* /
establecerTiempo de espera (fn, tiempo de espera) {
// declarar como variables para que estén correctamente disponibles en la función de tiempo de espera
// eslint-disable-next-line
var timeoutId, disponerFn;
fn = Fn.bind(esto, fn);
this.clearTimersOnDispose_();
timeoutId = ventana.setTimeout(() => {
if (this.setTimeoutIds_.has(timeoutId)) {
this.setTimeoutIds_.delete(timeoutId);
}
fn();
}, timeout);
this.setTimeoutIds_.add(timeoutId);
devuelve timeoutId;
}
/**
* Borra un tiempo de espera que se crea a través de `window.setTimeout` o
* {@link Component#setTimeout}. Si establece un tiempo de espera a través de {@link Component#setTimeout}
* use esta función en lugar de `window.clearTimout`. Si no te dispones
* ¡El oyente no se limpiará hasta {@link Component#dispose}!
*
* @param {número} timeoutId
* La identificación del tiempo de espera para borrar. El valor de retorno de
* {@link Component#setTimeout} o `window.setTimeout`.
*
* @return {número}
* Devuelve el ID de tiempo de espera que se borró.
*
* @ver [Similar a]{@enlace https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout}
* /
clearTimeout(timeoutId) {
if (this.setTimeoutIds_.has(timeoutId)) {
this.setTimeoutIds_.delete(timeoutId);
ventana.clearTimeout(timeoutId);
}
devuelve timeoutId;
}
/**
* Crea una función que se ejecuta cada `x` milisegundos. Esta función es un envoltorio
* alrededor de `window.setInterval`. Sin embargo, hay algunas razones para usar este.
* 1. Se borra a través de {@link Component#clearInterval} cuando
* Se llama a {@link Component#dispose}.
* 2. La devolución de llamada de la función será {@link Component~GenericCallback}
*
* @param {Componente~GenericCallback} fn
* La función para ejecutar cada `x` segundos.
*
* @param {número} intervalo
* Ejecuta la función especificada cada `x` milisegundos.
*
* @return {número}
* Devuelve una identificación que se puede usar para identificar el intervalo. También se puede utilizar en
* {@link Component#clearInterval} para borrar el intervalo.
*
* @escucha Componente#dispose
* @ver [Similar a]{@enlace https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval}
* /
establecerIntervalo(fn, intervalo) {
fn = Fn.bind(esto, fn);
this.clearTimersOnDispose_();
const intervaloId = ventana.setInterval(fn, intervalo);
this.setIntervalIds_.add(intervalId);
ID de intervalo de retorno;
}
/**
* Borra un intervalo que se crea a través de `window.setInterval` o
* {@link Component#setInterval}. Si establece un intervalo a través de {@link Component#setInterval}
* use esta función en lugar de `window.clearInterval`. Si no te dispones
* ¡El oyente no se limpiará hasta {@link Component#dispose}!
*
* @param {número} ID de intervalo
* El id del intervalo a borrar. El valor de retorno de
* {@link Component#setInterval} o `window.setInterval`.
*
* @return {número}
* Devuelve el ID de intervalo que se borró.
*
* @ver [Similar a]{@enlace https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval}
* /
clearInterval(intervalId) {
if (this.setIntervalIds_.has(intervalId)) {
this.setIntervalIds_.delete(intervalId);
ventana.clearInterval(intervalId);
}
ID de intervalo de retorno;
}
/**
* Pone en cola una devolución de llamada para pasar a requestAnimationFrame (rAF), pero
* con algunas bonificaciones adicionales:
*
* - Admite navegadores que no admiten rAF recurriendo a
* {@link Component#setTimeout}.
*
* - La devolución de llamada se convierte en un {@link Component~GenericCallback} (es decir,
* vinculado al componente).
*
* - La cancelación automática de la devolución de llamada rAF se maneja si el componente
* se elimina antes de que se llame.
*
* @param {Componente~GenericCallback} fn
* Una función que se vinculará a este componente y se ejecutará solo
* antes del próximo repintado del navegador.
*
* @return {número}
* Devuelve un ID de rAF que se utiliza para identificar el tiempo de espera. Puede
* también se puede usar en {@link Component#cancelAnimationFrame} para cancelar
* la devolución de llamada del cuadro de animación.
*
* @escucha Componente#dispose
* @ver [Similar a]{@link https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame}
* /
solicitudAnimationFrame(fn) {
// Vuelve a usar un temporizador.
if (!this.supportsRaf_) {
devolver esto.setTimeout(fn, 1000/60);
}
this.clearTimersOnDispose_();
// declarar como variables para que estén correctamente disponibles en la función rAF
// eslint-disable-next-line
id de var;
fn = Fn.bind(esto, fn);
id = ventana.requestAnimationFrame(() => {
if (this.rafIds_.has(id)) {
this.rafIds_.delete(id);
}
fn();
});
this.rafIds_.add(id);
identificación de retorno;
}
/**
* Solicite un cuadro de animación, pero solo una animación con nombre
* el marco se pondrá en cola. Nunca se agregará otro hasta que
* termina el anterior.
*
* @param {cadena} nombre
* El nombre para dar a esta solicitudAnimationFrame
*
* @param {Componente~GenericCallback} fn
* Una función que se vinculará a este componente y se ejecutará solo
* antes del próximo repintado del navegador.
* /
requestNamedAnimationFrame(nombre, fn) {
if (este.namedRafs_.has(nombre)) {
devolver;
}
this.clearTimersOnDispose_();
fn = Fn.bind(esto, fn);
const id = this.requestAnimationFrame(() => {
fn();
if (este.namedRafs_.has(nombre)) {
this.namedRafs_.delete(nombre);
}
});
this.namedRafs_.set(nombre, id);
devolver nombre;
}
/**
* Cancela un cuadro de animación con nombre actual, si existe.
*
* @param {cadena} nombre
* El nombre de la requestAnimationFrame para cancelar.
* /
cancelNamedAnimationFrame(nombre) {
if (!this.namedRafs_.has(nombre)) {
devolver;
}
this.cancelAnimationFrame(this.namedRafs_.get(nombre));
this.namedRafs_.delete(nombre);
}
/**
* Cancela una devolución de llamada en cola pasada a {@link Component#requestAnimationFrame}
* (RAF).
*
* Si pone en cola una devolución de llamada de rAF a través de {@link Component#requestAnimationFrame},
* use esta función en lugar de `window.cancelAnimationFrame`. si no lo haces,
* ¡Su detector de disposición no se limpiará hasta {@link Component#dispose}!
*
* ID de @param {número}
* El rAF ID para borrar. El valor de retorno de {@link Component#requestAnimationFrame}.
*
* @return {número}
* Devuelve el ID de rAF que se borró.
*
* @ver [Similar a]{@enlace https://developer.mozilla.org/en-US/docs/Web/API/window/cancelAnimationFrame}
* /
cancelAnimationFrame(id) {
// Vuelve a usar un temporizador.
if (!this.supportsRaf_) {
devolver esto.clearTimeout(id);
}
if (this.rafIds_.has(id)) {
this.rafIds_.delete(id);
ventana.cancelAnimationFrame(id);
}
identificación de retorno;
}
/**
* Una función para configurar `requestAnimationFrame`, `setTimeout`,
* y `setInterval`, borrando al desechar.
*
* > Anteriormente, cada temporizador agregado y eliminado dispone de oyentes por sí solo.
* Para un mejor rendimiento, se decidió agruparlos a todos y usar `Set`s
* para realizar un seguimiento de los identificadores de temporizador pendientes.
*
* @privado
* /
clearTimersOnDispose_() {
if (this.clearingTimersOnDispose_) {
devolver;
}
this.clearingTimersOnDispose_ = true;
this.one('dispose', () => {
[
['namedRafs_', 'cancelNamedAnimationFrame'],
['rafIds_', 'cancelAnimationFrame'],
['setTimeoutIds_', 'clearTimeout'],
['setIntervalIds_', 'clearInterval']
].forEach(([idNombre, cancelarNombre]) => {
// para una tecla `Set` será en realidad el valor de nuevo
// entonces paraCada((val,val) => ` pero para mapas queremos usar
// la clave.
este[idNombre].forEach((valor, clave) => this[cancelName](clave));
});
this.clearingTimersOnDispose_ = falso;
});
}
/**
* Registre un `Componente` con `videojs` dado el nombre y el componente.
*
* > NOTA: {@link Tech}s no debe registrarse como un 'Componente'. {@link Tech}s
* debe registrarse usando {@link Tech.registerTech} o
* {@enlace videojs:videojs.registerTech}.
*
* > NOTA: Esta función también se puede ver en videojs como
* {@enlace videojs:videojs.registerComponent}.
*
* @param {cadena} nombre
* El nombre del `Componente` a registrar.
*
* @param {Componente} Componente para registrar
* La clase `Componente` a registrar.
*
* @return {Componente}
* El `Componente` que fue registrado.
* /
Componente de registro estático (nombre, Componente a registro) {
if (tipo de nombre !== 'cadena' || !nombre) {
throw new Error(`Nombre de componente ilegal, "${name}"; debe ser una cadena no vacía.`);
}
const Tecnología = Componente.getComponent('Tecnología');
// Necesitamos asegurarnos de que esta verificación solo se realice si Tech se ha registrado.
const isTech = Tecnología && Tech.isTech(ComponenteParaRegistrar);
const isComp = Componente === ComponenteParaRegistrar ||
Componente.prototipo.isPrototypeOf(ComponentToRegister.prototype);
if (esTec || !isComp) {
deja razonar;
si (tecnología) {
razón = 'los técnicos deben registrarse mediante Tech.registerTech()';
} else {
razón = 'debe ser una subclase de Componente';
}
throw new Error(`Componente ilegal, "${nombre}"; ${razón}.`);
}
nombre = toTitleCase(nombre);
if (!Componente.componentes_) {
Componente.componentes_ = {};
}
const Jugador = Componente.getComponent('Jugador');
if (nombre === 'Jugador' && Jugador && jugador.jugadores) {
const jugadores = Jugador.jugadores;
const playerNames = Object.keys(players);
// Si tenemos jugadores que fueron descartados, su nombre seguirá siendo
// en Jugadores.jugadores. Entonces, debemos recorrer y verificar que el valor
// para cada elemento no es nulo. Esto permite el registro del componente Player
// después de que se hayan eliminado todos los jugadores o antes de que se haya creado alguno.
si (jugadores &&
nombredeljugador.longitud > 0 &&
playerNames.map((pname) => jugadores[pname]).every(Boolean)) {
throw new Error('No se puede registrar el componente del reproductor después de que se haya creado el reproductor');
}
}
Componente.componentes_[nombre] = ComponenteParaRegistrar;
Component.components_[toLowerCase(nombre)] = ComponentToRegister;
volver ComponenteParaRegistrar;
}
/**
* Obtener un 'Componente' basado en el nombre con el que fue registrado.
*
* @param {cadena} nombre
* El Nombre del componente a obtener.
*
* @return {Componente}
* El 'Componente' que se registró con el nombre de pila.
* /
getComponent estático (nombre) {
if (!nombre || !Componente.componentes_) {
devolver;
}
return Componente.componentes_[nombre];
}
}
/**
* Si este componente admite o no `requestAnimationFrame`.
*
* Esto se expone principalmente con fines de prueba.
*
* @privado
* @tipo {Booleano}
* /
Component.prototype.supportsRaf_ = typeof window.requestAnimationFrame === 'función' &&
typeof window.cancelAnimationFrame === 'función';
Componente.registerComponent('Componente', Componente);
exportar componente predeterminado;