/**
* @Datei seek-bar.js
* /
import Slider from '../../slider/slider.js';
importiere Komponente aus '../../component.js';
importiere {IS_IOS, IS_ANDROID} aus '../../utils/browser.js';
import * as Dom from '../../utils/dom.js';
import * as Fn from '../../utils/fn.js';
import formatTime from '../../utils/format-time.js';
importiere {silencePromise} von '../../utils/promise';
import keycode from 'keycode';
dokument aus 'global/document' importieren;
importieren './load-progress-bar.js';
importieren './play-progress-bar.js';
importieren './mouse-time-display.js';
// Die Anzahl der Sekunden, um die die `step*`-Funktionen die Zeitleiste verschieben.
const STEP_SECONDS = 5;
// Der Multiplikator von STEP_SECONDS, mit dem PgUp/PgDown die Zeitleiste bewegen.
const PAGE_KEY_MULTIPLIER = 12;
/**
* Suchleiste und Container für die Fortschrittsbalken. Verwendet {@link PlayProgressBar}
* als seine "Bar".
*
* @extends Schieberegler
* /
class SeekBar extends Slider {
/**
* Erzeugt eine Instanz dieser Klasse.
*
* @param {Player} Spieler
* Der `Player`, dem diese Klasse zugeordnet werden soll.
*
* @param {Object} [Optionen]
* Der Schlüssel/Wertspeicher der Playeroptionen.
* /
constructor(spieler, optionen) {
super(Spieler, Optionen);
this.setEventHandlers_();
}
/**
* Legt die Ereignisbehandler fest
*
* @privat
* /
setEventHandlers_() {
this.update_ = Fn.bind(this, this.update);
this.update = Fn.throttle(this.update_, Fn.UPDATE_REFRESH_INTERVAL);
this.on(this.player_, ['ended', 'durationchange', 'timeupdate'], this.update);
if (this.player_.liveTracker) {
this.on(this.player_.liveTracker, 'liveedgechange', this.update);
}
// Beim Abspielen muss der Fortschrittsbalken reibungslos aktualisiert werden
// über ein Intervall
this.updateInterval = null;
this.enableIntervalHandler_ = (e) => this.enableInterval_(e);
this.disableIntervalHandler_ = (e) => this.disableInterval_(e);
this.on(this.player_, ['playing'], this.enableIntervalHandler_);
this.on(this.player_, ['ended', 'pause', 'waiting'], this.disableIntervalHandler_);
// Wir brauchen den Wiedergabefortschritt nicht zu aktualisieren, wenn das Dokument ausgeblendet ist,
// Außerdem führt dies zu einem Anstieg der CPU-Leistung und schließlich zum Absturz der Seite im IE11.
wenn ('hidden' in Dokument && 'visibilityState' in Dokument) {
this.on(document, 'visibilitychange', this.toggleVisibility_);
}
}
toggleVisibility_(e) {
if (document.visibilityState === 'hidden') {
this.cancelNamedAnimationFrame('SeekBar#update');
this.cancelNamedAnimationFrame('Slider#update');
this.disableInterval_(e);
} else {
if (!this.player_.ended() && !this.player_.paused()) {
this.enableInterval_();
}
// wir haben gerade wieder auf die Seite gewechselt und es könnte jemand suchen, also aktualisieren Sie so schnell wie möglich
this.update();
}
}
enableInterval_() {
if (this.updateInterval) {
rückkehr;
}
this.updateInterval = this.setInterval(this.update, Fn.UPDATE_REFRESH_INTERVAL);
}
disableInterval_(e) {
if (this.player_.liveTracker && this.player_.liveTracker.isLive() && e && e.type !== 'ended') {
rückkehr;
}
if (!this.updateInterval) {
rückkehr;
}
this.clearInterval(this.updateInterval);
this.updateInterval = null;
}
/**
* Das DOM-Element der Komponente erstellen
*
* @return {Element}
* Das Element, das erstellt wurde.
* /
createEl() {
return super.createEl('div', {
className: 'vjs-fortschritt-halter'
}, {
aria-label': this.localize('Fortschrittsbalken')
});
}
/**
* Diese Funktion aktualisiert den Fortschrittsbalken der Wiedergabe und die Barrierefreiheit
* attribute an das übergebene Objekt.
*
* @param {EventTarget~Event} [event]
* Das "timeupdate"- oder "ended"-Ereignis, das diesen Vorgang ausgelöst hat.
*
* @listens Player#timeupdate
*
* @return {number}
* Der aktuelle Prozentsatz auf eine Zahl von 0-1
* /
update(event) {
// Aktualisierungen ignorieren, solange die Registerkarte ausgeblendet ist
if (document.visibilityState === 'hidden') {
rückkehr;
}
const percent = super.update();
this.requestNamedAnimationFrame('SeekBar#update', () => {
const currentTime = this.player_.ended() ?
this.player_.duration() : this.getCurrentTime_();
const liveTracker = this.player_.liveTracker;
let duration = this.player_.duration();
if (liveTracker && liveTracker.isLive()) {
dauer = this.player_.liveTracker.liveCurrentTime();
}
if (this.percent_ !== percent) {
// Maschinenlesbarer Wert des Fortschrittsbalkens (Prozentsatz der Fertigstellung)
this.el_.setAttribute('aria-valuenow', (percent * 100).toFixed(2));
this.percent_ = percent;
}
if (this.currentTime_ !== currentTime || this.duration_ !== duration) {
// Für Menschen lesbarer Wert des Fortschrittsbalkens (Zeit bis zur Fertigstellung)
this.el_.setAttribute(
aria-valuetext',
this.localize(
fortschrittsbalken-Zeitmessung: currentTime={1} duration={2}',
[formatTime(currentTime, duration),
formatTime(Dauer, Dauer)],
'{1} von {2}'
)
);
this.currentTime_ = currentTime;
this.duration_ = duration;
}
// Aktualisieren Sie den Zeit-Tooltip des Fortschrittsbalkens mit der aktuellen Zeit
if (this.bar) {
this.bar.update(Dom.getBoundingClientRect(this.el()), this.getProgress());
}
});
prozent zurück;
}
/**
* Verhindern Sie, dass liveThreshold die Suchanfragen so aussehen lässt, als ob sie
* aus Sicht der Nutzer nicht stattfinden.
*
* @param {Nummer} ct
* die aktuelle Zeit, um zu versuchen
* /
userSeek_(ct) {
if (this.player_.liveTracker && this.player_.liveTracker.isLive()) {
this.player_.liveTracker.nextSeekedFromUser();
}
this.player_.currentTime(ct);
}
/**
* Ermittelt den Wert der aktuellen Zeit, ermöglicht aber ein reibungsloses Scrubbing,
* wenn der Spieler nicht mithalten kann.
*
* @return {number}
* Der aktuelle Zeitwert, der angezeigt werden soll
*
* @privat
* /
getCurrentTime_() {
return (this.player_.scrubbing()) ?
this.player_.getCache().currentTime :
this.player_.currentTime();
}
/**
* Ermitteln Sie den Prozentsatz der bisher abgespielten Medien.
*
* @return {number}
* Der Prozentsatz der bisher abgespielten Medien (0 bis 1).
* /
getPercent() {
const currentTime = this.getCurrentTime_();
prozent lassen;
const liveTracker = this.player_.liveTracker;
if (liveTracker && liveTracker.isLive()) {
prozent = (currentTime - liveTracker.seekableStart()) / liveTracker.liveWindow();
// verhindern, dass sich der Prozentsatz an der aktiven Kante ändert
if (liveTracker.atLiveEdge()) {
prozent = 1;
}
} else {
prozent = currentTime / this.player_.duration();
}
prozent zurück;
}
/**
* Maus auf der Suchleiste nach unten führen
*
* @param {EventTarget~Event} event
* Das "Mousedown"-Ereignis, das diesen Vorgang ausgelöst hat.
*
* @listens mousedown
* /
handleMouseDown(event) {
if (!Dom.isSingleLeftClick(event)) {
rückkehr;
}
// Stoppen Sie die Ereignisfortpflanzung, um ein doppeltes Auslösen in progress-control.js zu verhindern
event.stopPropagation();
this.videoWasPlaying = !this.player_.paused();
this.player_.pause();
super.handleMouseDown(event);
}
/**
* Mausbewegung auf der Suchleiste behandeln
*
* @param {EventTarget~Event} event
* Das Ereignis "Mausbewegung", das dies ausgelöst hat.
* @param {boolean} mouseDown dies ist ein Flag, das auf true gesetzt werden sollte, wenn `handleMouseMove` direkt aufgerufen wird. Es erlaubt uns, Dinge zu überspringen, die nicht passieren sollten, wenn sie von der Maus nach unten kommen, aber bei einer normalen Mausbewegung passieren sollten. Standardmäßig ist false eingestellt
*
* @listens mousemove
* /
handleMouseMove(event, mouseDown = false) {
if (!Dom.isSingleLeftClick(event)) {
rückkehr;
}
if (!mouseDown && !this.player_.scrubbing()) {
this.player_.scrubbing(true);
}
let newTime;
const distance = this.calculateDistance(event);
const liveTracker = this.player_.liveTracker;
if (!liveTracker || !liveTracker.isLive()) {
newTime = distance * this.player_.duration();
// Lassen Sie das Video während des Scrubbing nicht enden.
if (newTime === this.player_.duration()) {
newTime = newTime - 0.1;
}
} else {
wenn (Abstand >= 0,99) {
liveTracker.seekToLiveEdge();
rückkehr;
}
const seekableStart = liveTracker.seekableStart();
const seekableEnd = liveTracker.liveCurrentTime();
newTime = seekableStart + (Entfernung * liveTracker.liveWindow());
// Lassen Sie das Video während des Scrubbing nicht enden.
if (newTime >= seekableEnd) {
newTime = seekableEnd;
}
// Präzisionsunterschiede kompensieren, damit currentTime nicht kleiner ist
// als suchbarer Start
wenn (newTime <= seekableStart) {
newTime = seekableStart + 0.1;
}
// Auf Android kann seekableEnd manchmal Infinity sein,
// Dies führt dazu, dass newTime unendlich ist, was bedeutet
// keine gültige currentTime.
if (newTime === Infinity) {
rückkehr;
}
}
// Neue Zeit einstellen (dem Spieler sagen, dass er nach der neuen Zeit suchen soll)
this.userSeek_(newTime);
}
enable() {
super.enable();
const mouseTimeDisplay = this.getChild('mouseTimeDisplay');
if (!mouseTimeDisplay) {
rückkehr;
}
mouseTimeDisplay.show();
}
deaktivieren() {
super.disable();
const mouseTimeDisplay = this.getChild('mouseTimeDisplay');
if (!mouseTimeDisplay) {
rückkehr;
}
mouseTimeDisplay.hide();
}
/**
* Maus auf der Suchleiste nach oben führen
*
* @param {EventTarget~Event} event
* Das `Mouseup'-Ereignis, das die Ausführung dieses Vorgangs verursacht hat.
*
* @listens mouseup
* /
handleMouseUp(event) {
super.handleMouseUp(event);
// Stoppen Sie die Ereignisfortpflanzung, um ein doppeltes Auslösen in progress-control.js zu verhindern
if (Ereignis) {
event.stopPropagation();
}
this.player_.scrubbing(false);
/**
* Timeupdate auslösen, weil die Suche beendet ist und sich die Zeit geändert hat.
* Dies ist besonders nützlich, wenn der Player angehalten wird, um die Zeitanzeige zu steuern.
*
* @event Tech#timeupdate
* @Typ {EventTarget~Event}
* /
this.player_.trigger({ type: 'timeupdate', target: this, manuallyTriggered: true });
if (this.videoWasPlaying) {
silencePromise(this.player_.play());
} else {
// Wir sind fertig mit der Suche und die Zeit hat sich geändert.
// Wenn der Player pausiert, muss die korrekte Zeit in der Suchleiste angezeigt werden.
this.update_();
}
}
/**
* Schnelleres Vorwärtsbewegen für Benutzer, die nur die Tastatur benutzen
* /
stepForward() {
this.userSeek_(this.player_.currentTime() + STEP_SECONDS);
}
/**
* Schnellerer Rücklauf für Benutzer, die nur die Tastatur benutzen
* /
stepBack() {
this.userSeek_(this.player_.currentTime() - STEP_SECONDS);
}
/**
* Schaltet den Wiedergabestatus des Players um
* Diese Funktion wird aufgerufen, wenn die Eingabetaste oder die Leertaste in der Suchleiste gedrückt wird
*
* @param {EventTarget~Event} event
* Das "Keydown"-Ereignis, das zum Aufruf dieser Funktion geführt hat
*
* /
handleAction(event) {
if (this.player_.paused()) {
this.player_.play();
} else {
this.player_.pause();
}
}
/**
* Wird aufgerufen, wenn diese SeekBar den Fokus hat und eine Taste gedrückt wird.
* Unterstützt die folgenden Tasten:
*
* Leertaste oder Eingabetaste lösen ein Klickereignis aus
* Die Home-Taste springt an den Anfang der Zeitleiste
* Taste Ende bewegt sich zum Ende der Zeitleiste
* Die Zifferntasten "0" bis "9" bewegen sich auf 0%, 10% ... 80%, 90% des Zeitrahmens
* PageDown-Taste geht einen größeren Schritt zurück als ArrowDown
* Taste PageUp bewegt sich einen großen Schritt vorwärts
*
* @param {EventTarget~Event} event
* Das "Keydown"-Ereignis, das zum Aufruf dieser Funktion geführt hat.
*
* @listens keydown
* /
handleKeyDown(event) {
const liveTracker = this.player_.liveTracker;
if (keycode.isEventKey(event, 'Space') || keycode.isEventKey(event, 'Enter')) {
event.preventDefault();
event.stopPropagation();
this.handleAction(event);
} else if (keycode.isEventKey(event, 'Home')) {
event.preventDefault();
event.stopPropagation();
this.userSeek_(0);
} else if (keycode.isEventKey(event, 'End')) {
event.preventDefault();
event.stopPropagation();
if (liveTracker && liveTracker.isLive()) {
this.userSeek_(liveTracker.liveCurrentTime());
} else {
this.userSeek_(this.player_.duration());
}
} else if (/^[0-9]$/.test(keycode(event))) {
event.preventDefault();
event.stopPropagation();
const gotoFraction = (keycode.codes[keycode(event)] - keycode.codes['0']) * 10.0 / 100.0;
if (liveTracker && 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 {
// Übergeben Sie die Behandlung von nicht unterstützten Tasten nach oben
super.handleKeyDown(event);
}
}
dispose() {
this.disableInterval_();
this.off(this.player_, ['ended', 'durationchange', 'timeupdate'], this.update);
if (this.player_.liveTracker) {
this.off(this.player_.liveTracker, 'liveedgechange', this.update);
}
this.off(this.player_, ['playing'], this.enableIntervalHandler_);
this.off(this.player_, ['ended', 'pause', 'waiting'], this.disableIntervalHandler_);
// Wir brauchen den Wiedergabefortschritt nicht zu aktualisieren, wenn das Dokument ausgeblendet ist,
// Außerdem führt dies zu einem Anstieg der CPU-Leistung und schließlich zum Absturz der Seite im IE11.
wenn ('hidden' in Dokument && 'visibilityState' in Dokument) {
this.off(document, 'visibilitychange', this.toggleVisibility_);
}
super.dispose();
}
}
/**
* Standardoptionen für die Suchleiste
*
* @Typ {Objekt}
* @privat
* /
SeekBar.prototype.options_ = {
kinder: [
loadProgressBar',
playProgressBar'
],
barName: 'playProgressBar'
};
// MouseTimeDisplay-Tooltips sollten einem Player auf mobilen Geräten nicht hinzugefügt werden
if (!IS_IOS && !IS_ANDROID) {
SeekBar.prototype.options_.children.splice(1, 0, 'mouseTimeDisplay');
}
Component.registerComponent('SeekBar', SeekBar);
standard SeekBar exportieren;