/**
* @archivo buscar-bar.js
* /
importar control deslizante desde '../../slider/slider.js';
importar componente desde '../../component.js';
importar {IS_IOS, IS_ANDROID} desde '../../utils/browser.js';
importar * como Dom desde '../../utils/dom.js';
importar * como Fn desde '../../utils/fn.js';
importar formatTime desde '../../utils/format-time.js';
importar {silencePromise} desde '../../utils/promise';
importar código clave desde 'código clave';
importar documento desde 'global/document';
importar './load-progress-bar.js';
importar './play-progress-bar.js';
importar './mouse-time-display.js';
// El número de segundos que las funciones `step*` mueven la línea de tiempo.
constante PASO_SEGUNDOS = 5;
// El multiplicador de STEP_SECONDS que PgUp/PgDown mueven la línea de tiempo.
const PAGE_KEY_MULTIPLIER = 12;
/**
* Barra de búsqueda y contenedor para las barras de progreso. Utiliza {@link PlayProgressBar}
* como su `bar`.
*
* @extiende el control deslizante
* /
clase SeekBar extiende el control deslizante {
/**
* 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 del jugador.
* /
constructor(jugador, opciones) {
super(jugador, opciones);
this.setEventHandlers_();
}
/**
* Establece los controladores de eventos
*
* @privado
* /
setEventHandlers_() {
this.update_ = Fn.bind(this, this.update);
this.update = Fn.throttle(this.update_, Fn.UPDATE_REFRESH_INTERVAL);
this.on(this.player_, ['finalizado', 'durationchange', 'timeupdate'], this.update);
si (this.player_.liveTracker) {
this.on(this.player_.liveTracker, 'liveedgechange', this.update);
}
// al jugar, asegurémonos de actualizar sin problemas la barra de progreso del juego
// a través de un intervalo
this.updateInterval = null;
this.enableIntervalHandler_ = (e) => this.enableInterval_(e);
this.disableIntervalHandler_ = (e) => this.disableInterval_(e);
this.on(this.player_, ['jugando'], this.enableIntervalHandler_);
this.on(this.player_, ['finalizado', 'pausa', 'esperando'], this.disableIntervalHandler_);
// no necesitamos actualizar el progreso de la reproducción si el documento está oculto,
// también, esto hace que la CPU se dispare y finalmente bloquee la página en IE11.
if ('oculto' en el documento && 'estado de visibilidad' en el documento) {
this.on(documento, 'cambio de visibilidad', this.toggleVisibility_);
}
}
alternarVisibilidad_(e) {
if (document.visibilityState === 'oculto') {
this.cancelNamedAnimationFrame('SeekBar#update');
this.cancelNamedAnimationFrame('Slider#update');
this.disableInterval_(e);
} else {
si (!este.jugador_.terminado() && !este.jugador_.pausado()) {
this.enableInterval_();
}
// acabamos de volver a la página y es posible que alguien esté mirando, así que actualice lo antes posible
esta.actualización();
}
}
habilitarIntervalo_() {
if (este.intervalo de actualización) {
devolver;
}
this.updateInterval = this.setInterval(this.update, Fn.UPDATE_REFRESH_INTERVAL);
}
deshabilitarIntervalo_(e) {
si (this.player_.liveTracker && this.player_.liveTracker.isLive() && mi && e.type !== 'terminado') {
devolver;
}
if (!this.updateInterval) {
devolver;
}
este.clearInterval(este.updateInterval);
this.updateInterval = null;
}
/**
* Crear el elemento DOM del 'Componente'
*
* @return {Elemento}
* El elemento que se creó.
* /
crearEl() {
return super.createEl('div', {
className: 'vjs-progreso-titular'
}, {
'aria-label': this.localize('Barra de progreso')
});
}
/**
* Esta función actualiza la barra de progreso de reproducción y la accesibilidad.
* atributos a todo lo que se pasa.
*
* @param {Objetivo de evento~Evento} [evento]
* El evento 'timeupdate' o 'finalizado' que hizo que esto se ejecutara.
*
* @escucha Player#timeupdate
*
* @return {número}
* El porcentaje actual en un número de 0-1
* /
actualizar (evento) {
// ignora las actualizaciones mientras la pestaña está oculta
if (document.visibilityState === 'oculto') {
devolver;
}
porcentaje constante = super.update();
this.requestNamedAnimationFrame('SeekBar#update', () => {
const horaActual = this.player_.ended() ?
this.player_.duration() : this.getCurrentTime_();
const liveTracker = this.player_.liveTracker;
let duración = this.player_.duration();
si (rastreador en vivo && liveTracker.isLive()) {
duración = this.player_.liveTracker.liveCurrentTime();
}
if (this.percent_ !== percent) {
// valor legible por máquina de la barra de progreso (porcentaje completado)
this.el_.setAttribute('aria-valuenow', (porcentaje * 100).toFixed(2));
this.percent_ = porcentaje;
}
if (this.currentTime_ !== currentTime || this.duration_ !== duración) {
// valor legible por humanos de la barra de progreso (tiempo completo)
this.el_.setAttribute(
'aria-valuetext',
esto.localizar(
'tiempo de la barra de progreso: horaActual={1} duración={2}',
[formatoTiempo(horaActual, duración),
formatTime(duración, duración)],
'{1 de 2}'
)
);
this.currentTime_ = currentTime;
this.duration_ = duración;
}
// actualizar la información sobre herramientas de la barra de progreso con la hora actual
si (esta.barra) {
this.bar.update(Dom.getBoundingClientRect(this.el()), this.getProgress());
}
});
porcentaje de retorno;
}
/**
* Evite que liveThreshold haga que las búsquedas parezcan
* no están sucediendo desde la perspectiva del usuario.
*
* @param {número} ct
* tiempo actual para buscar
* /
usuarioSeek_(ct) {
si (this.player_.liveTracker && this.player_.liveTracker.isLive()) {
this.player_.liveTracker.nextSeekedFromUser();
}
this.player_.currentTime(ct);
}
/**
* Obtenga el valor de la hora actual, pero permite un lavado suave,
* cuando el jugador no puede seguir el ritmo.
*
* @return {número}
* El valor de tiempo actual para mostrar
*
* @privado
* /
getHoraActual_() {
volver (this.player_.scrubbing()) ?
this.player_.getCache().currentTime :
this.player_.currentTime();
}
/**
* Obtenga el porcentaje de contenido multimedia reproducido hasta el momento.
*
* @return {número}
* El porcentaje de medios reproducidos hasta ahora (0 a 1).
* /
obtenerPorcentaje() {
const horaActual = this.getCurrentTime_();
sea por ciento;
const liveTracker = this.player_.liveTracker;
si (rastreador en vivo && liveTracker.isLive()) {
porcentaje = (horaActual - liveTracker.seekableStart()) / liveTracker.liveWindow();
// evita que el porcentaje cambie en el borde vivo
si (liveTracker.atLiveEdge()) {
porcentaje = 1;
}
} else {
porcentaje = horaActual / this.player_.duration();
}
porcentaje de retorno;
}
/**
* Maneje el mouse hacia abajo en la barra de búsqueda
*
* @param {EventTarget~Evento} evento
* El evento `mousedown` que causó que esto se ejecutara.
*
* @escucha mousedown
* /
manejarRatónAbajo(evento) {
if (!Dom.isSingleLeftClick(evento)) {
devolver;
}
// Detener la propagación de eventos para evitar el doble disparo en el progreso de control.js
event.stopPropagation();
this.videoWasPlaying = !this.player_.paused();
este.jugador_.pausa();
super.handleMouseDown(evento);
}
/**
* Manejar el movimiento del mouse en la barra de búsqueda
*
* @param {EventTarget~Evento} evento
* El evento `mousemove` que causó que esto se ejecutara.
* @param {boolean} mouseDown este es un indicador que debe establecerse en verdadero si `handleMouseMove` se llama directamente. Nos permite omitir cosas que no deberían suceder si vienen con el mouse hacia abajo, pero deberían suceder en el controlador de movimiento del mouse normal. Predeterminado a falso
*
* @escucha movimiento del ratón
* /
handleMouseMove(evento, mouseDown = false) {
if (!Dom.isSingleLeftClick(evento)) {
devolver;
}
si (!mouseDown && !este.jugador_.fregado()) {
this.player_.scrubbing(verdadero);
}
dejar nuevoTiempo;
const distancia = this.calculateDistance(evento);
const liveTracker = this.player_.liveTracker;
if (!liveTracker || !liveTracker.isLive()) {
newTime = distancia * this.player_.duration();
// No dejes que el video termine mientras se limpia.
if (newTime === this.player_.duration()) {
nuevoTiempo = nuevoTiempo - 0.1;
}
} else {
si (distancia > = 0,99) {
LiveTracker.seekToLiveEdge();
devolver;
}
const seekableStart = liveTracker.seekableStart();
const seekableEnd = liveTracker.liveCurrentTime();
newTime = seekableStart + (distancia * liveTracker.liveWindow());
// No dejes que el video termine mientras se limpia.
si (nuevoTiempo > = fin buscable) {
newTime = fin buscable;
}
// Compensar las diferencias de precisión para que el tiempo actual no sea menor
// que inicio buscable
si (nuevoTiempo < = inicio buscable) {
nuevoTiempo = inicioBuscable + 0.1;
}
// En Android seekableEnd puede ser Infinito a veces,
// esto hará que newTime sea Infinity, que es
// no es una hora actual válida.
if (nuevoTiempo === Infinito) {
devolver;
}
}
// Establecer una nueva hora (dígale al jugador que busque una nueva hora)
this.userSeek_(newTime);
}
permitir() {
super.enable();
const mouseTimeDisplay = this.getChild('mouseTimeDisplay');
if (!mouseTimeDisplay) {
devolver;
}
mouseTimeDisplay.show();
}
desactivar() {
super.disable();
const mouseTimeDisplay = this.getChild('mouseTimeDisplay');
if (!mouseTimeDisplay) {
devolver;
}
mouseTimeDisplay.hide();
}
/**
* Manejar el mouse hacia arriba en la barra de búsqueda
*
* @param {EventTarget~Evento} evento
* El evento `mouseup` que causó que esto se ejecutara.
*
* @escucha mouseup
* /
manejarMouseUp(evento) {
super.handleMouseUp(evento);
// Detener la propagación de eventos para evitar el doble disparo en el progreso de control.js
si (evento) {
event.stopPropagation();
}
this.player_.scrubbing(falso);
/**
* Active la actualización de la hora porque hemos terminado de buscar y la hora ha cambiado.
* Esto es particularmente útil si el reproductor está en pausa para cronometrar las pantallas de tiempo.
*
* @event Tech#timeupdate
* @type {Objetivo del evento~Evento}
* /
this.player_.trigger({ type: 'timeupdate', target: this, manualmente Triggered: true });
if (este.videoEstabaReproduciendo) {
PromesaSilencio(este.jugador_.jugar());
} else {
// Terminamos de buscar y el tiempo ha cambiado.
// Si el reproductor está en pausa, asegúrese de mostrar la hora correcta en la barra de búsqueda.
esto.actualizar_();
}
}
/**
* Avance más rápido para usuarios de solo teclado
* /
un paso adelante() {
this.userSeek_(this.player_.currentTime() + STEP_SECONDS);
}
/**
* Muévase más rápido y rebobine para usuarios de solo teclado
* /
Paso atrás() {
this.userSeek_(this.player_.currentTime() - STEP_SECONDS);
}
/**
* Cambia el estado de reproducción del reproductor
* Esto se llama cuando se usa enter o espacio en la barra de búsqueda
*
* @param {EventTarget~Evento} evento
* El evento `keydown` que provocó que se llamara a esta función
*
* /
manejarAcción(evento) {
if (este.jugador_.pausado()) {
este.jugador_.jugar();
} else {
este.jugador_.pausa();
}
}
/**
* Se llama cuando esta SeekBar tiene el foco y se presiona una tecla.
* Soporta las siguientes claves:
*
* La tecla Espacio o Intro activa un evento de clic
* La tecla de inicio se mueve al inicio de la línea de tiempo
* La tecla Finalizar se mueve al final de la línea de tiempo
* Las teclas de dígitos "0" a "9" se mueven a 0%, 10% ... 80%, 90% de la línea de tiempo
* La tecla PageDown retrocede un paso más grande que ArrowDown
* La tecla PageUp avanza un gran paso
*
* @param {EventTarget~Evento} evento
* El evento `keydown` que hizo que se llamara a esta función.
*
* @escucha tecla abajo
* /
handleKeyDown(evento) {
const liveTracker = this.player_.liveTracker;
if (keycode.isEventKey(evento, 'Espacio') || keycode.isEventKey(evento, 'Entrar')) {
event.preventDefault();
event.stopPropagation();
this.handleAction(evento);
} else if (keycode.isEventKey(evento, 'Inicio')) {
event.preventDefault();
event.stopPropagation();
este.userSeek_(0);
} else if (keycode.isEventKey(evento, 'Fin')) {
event.preventDefault();
event.stopPropagation();
si (rastreador en vivo && liveTracker.isLive()) {
this.userSeek_(liveTracker.liveCurrentTime());
} else {
this.userSeek_(this.player_.duration());
}
} else if (/^[0-9]$/.test(keycode(evento))) {
event.preventDefault();
event.stopPropagation();
const gotoFraction = (keycode.codes[keycode(evento)] - keycode.codes['0']) * 10.0 / 100.0;
si (rastreador en vivo && liveTracker.isLive()) {
this.userSeek_(liveTracker.seekableStart() + (liveTracker.liveWindow() * gotoFraction));
} else {
this.userSeek_(this.player_.duration() * gotoFraction);
}
} else if (keycode.isEventKey(event, 'PgDn')) {
event.preventDefault();
event.stopPropagation();
this.userSeek_(this.player_.currentTime() - (STEP_SECONDS * PAGE_KEY_MULTIPLIER));
} else if (keycode.isEventKey(event, 'PgUp')) {
event.preventDefault();
event.stopPropagation();
this.userSeek_(this.player_.currentTime() + (STEP_SECONDS * PAGE_KEY_MULTIPLIER));
} else {
// Pasar el manejo de keydown para claves no compatibles
super.handleKeyDown(evento);
}
}
disponer () {
this.disableInterval_();
this.off(this.player_, ['finalizado', 'durationchange', 'timeupdate'], this.update);
si (this.player_.liveTracker) {
this.off(this.player_.liveTracker, 'liveedgechange', this.update);
}
this.off(this.player_, ['jugando'], this.enableIntervalHandler_);
this.off(this.player_, ['finalizado', 'pausa', 'esperando'], this.disableIntervalHandler_);
// no necesitamos actualizar el progreso de la reproducción si el documento está oculto,
// también, esto hace que la CPU se dispare y finalmente bloquee la página en IE11.
if ('oculto' en el documento && 'estado de visibilidad' en el documento) {
this.off(document, 'visibilitychange', this.toggleVisibility_);
}
super.dispose();
}
}
/**
* Opciones predeterminadas para `SeekBar`
*
* @type {Objeto}
* @privado
* /
SeekBar.prototipo.opciones_ = {
niños: [
'cargar barra de progreso',
'playProgressBar'
],
barName: 'playProgressBar'
};
// La información sobre herramientas de MouseTimeDisplay no debe agregarse a un reproductor en dispositivos móviles
if (!IS_IOS && !IS_ANDROID) {
SeekBar.prototype.options_.children.splice(1, 0, 'mouseTimeDisplay');
}
Componente.registerComponent('BuscarBar', BuscarBar);
exportar SeekBar por defecto;