/**
* @file player.js
* /
//Komponente „Unterklassen“
importiere Komponente aus './component.js';
importiere {version} von '../../package.json';
dokument aus 'global/document' importieren;
import window from 'global/window';
importiere evented von './mixins/evented';
importiere {isEvented, addEventedCallback} aus '. /mixins/event ';
import * as Events aus './utils/events.js';
importiere * as Dom aus './utils/dom.js';
import * as Fn from './utils/fn.js';
importiere * als Guid aus './utils/guid.js';
importiere * as browser aus './utils/browser.js';
importiere {IE_VERSION, IS_CHROME, IS_WINDOWS} aus '. /utils/browser.js ';
import log, { createLogger } from './utils/log.js';
importiere {toTitleCase, TitleCaseEquals} aus '. /utils/string-cases.js ';
importiere {createTimeRange} aus '. /utils/time-ranges.js ';
importiere {bufferedPercent} aus '. /utils/buffer.js ';
importiere * als Stylesheet aus './utils/stylesheet.js';
importiere FullScreenAPI aus '. /fullscreen-api.js ';
importiere MediaError aus '. /media-error.js ';
importiere SafeParseTuple aus 'safe-json-parse/tuple';
importiere {assign} von './utils/obj';
importiere mergeOptions aus './utils/merge-options.js';
importiere {silencePromise, isPromise} aus '. /utils/promise ';
importiere TextTrackConverter aus '. /tracks/text-track-list-converter.js ';
import ModalDialog from './modal-dialog';
importiere Tech aus './tech/tech.js';
importiere * als Middleware aus '. /tech/middleware.js ';
importiere {ALL as TRACK_TYPES} aus '. /tracks/track-Typen ';
importiere FilterSource aus '. /utils/filter-source ';
importiere {getMimeType, findMimeType} aus '. /utils/mimetypes ';
importiere {hooks} aus '. /utils/hooks ';
importiere {isObject} von './utils/obj';
import keycode from 'keycode';
//Die folgenden Importe werden nur verwendet, um sicherzustellen, dass die entsprechenden Module
//sind immer im Paket video.js enthalten. Das Importieren der Module wird
//führe sie aus und sie registrieren sich bei video.js.
importieren '. /tech/loader.js ';
importieren '. /poster-image.js ';
importieren '. /tracks/text-track-display.js ';
importieren '. /loading-spinner.js ';
importieren '. /big-play-button.js ';
importieren '. /close-button.js ';
importieren '. /control-bar/control-bar.js ';
importieren '. /error-display.js ';
importieren '. /tracks/text-track-settings.js ';
importieren '. /resize-manager.js ';
importieren '. /live-tracker.js ';
//Importiere Html5-Technologie, zumindest um das ursprüngliche Video-Tag zu löschen.
importieren '. /tech/html5.js ';
//Die folgenden Tech-Events werden einfach erneut ausgelöst
//auf den Spieler, wenn sie passieren
const TECH_EVENTS_RETRIGGER = [
/**
* Wird ausgelöst, während der Benutzeragent Mediendaten herunterlädt.
*
* @event Spieler #progress
* @Typ {EventTarget~Event}
* /
/**
* Das `Progress`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @privat
* @method Spieler #handleTechProgress_
* @fires Spieler #progress
* @listens Technik #progress
* /
fortschritt",
/**
* Wird ausgelöst, wenn das Laden eines Audio/Videos abgebrochen wird.
*
* @event Spieler #abort
* @Typ {EventTarget~Event}
* /
/**
* Das `abort`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @privat
* @method Spieler #handleTechAbort_
* @fires Spieler #abort
* @listens Technik #abort
* /
abbruch",
/**
* Wird ausgelöst, wenn der Browser absichtlich keine Mediendaten abruft.
*
* @event Spieler #suspend
* @Typ {EventTarget~Event}
* /
/**
* Das `suspend`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @privat
* @method Spieler #handleTechSuspend_
* @fires Spieler #suspend
* @listens Technik #suspend
* /
aussetzen',
/**
* Wird ausgelöst, wenn die aktuelle Playlist leer ist.
*
* @event Spieler #emptied
* @Typ {EventTarget~Event}
* /
/**
* Löse das `emptied`-Ereignis erneut aus, das vom {@link Tech} ausgelöst wurde.
*
* @privat
* @method Spieler #handleTechEmptied_
* @fires Spieler #emptied
* @listens Technik #emptied
* /
geleert",
/**
* Wird ausgelöst, wenn der Browser versucht, Mediendaten abzurufen, Daten jedoch nicht verfügbar sind.
*
* @event Spieler #stalled
* @Typ {EventTarget~Event}
* /
/**
* Das `stalled`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @privat
* @method Spieler #handleTechStalled_
* @fires Spieler #stalled
* @listens Technik #stalled
* /
abgewürgt",
/**
* Wird ausgelöst, wenn der Browser Metadaten für das Audio/Video geladen hat.
*
* @Ereignis Player#geladenMetadaten
* @Typ {EventTarget~Event}
* /
/**
* Das `loadedmetadata`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @privat
* @method Spieler #handleTechLoadedmetadata_
* @fires Spieler #loadedmetadata
* @listens Tech#loadedmetadata
* /
'loadedmetadata',
/**
* Wird ausgelöst, wenn der Browser den aktuellen Frame des Audio/Videos geladen hat.
*
* @event Player#loadeddata
* @Typ {Ereignis}
* /
/**
* Das `loadeddata`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @privat
* @method Spieler #handleTechLoaddeddata_
* @fires Spieler #loadeddata
* @listens Technik #loadeddata
* /
'Geladene Daten',
/**
* Wird ausgelöst, wenn sich die aktuelle Wiedergabeposition geändert hat.
*
* @event Player#timeupdate
* @Typ {Ereignis}
* /
/**
* Das `timeupdate`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @privat
* @method Spieler #handleTechTimeUpdate_
* @fires Spieler #timeupdate
* @listens Technik #timeupdate
* /
timeupdate',
/**
* Wird ausgelöst, wenn sich die intrinsischen Abmessungen des Videos ändern
*
* @event Spieler #resize
* @Typ {Ereignis}
* /
/**
* Das `resize`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @privat
* @method Spieler #handleTechResize_
* @fires Spieler #resize
* @listens Technik #resize
* /
größe ändern",
/**
* Wird ausgelöst, wenn die Lautstärke geändert wurde
*
* @event Player#Lautstärkeänderung
* @Typ {Ereignis}
* /
/**
* Das `volumechange`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @privat
* @method Spieler #handleTechVolumechange_
* @fires Spieler #volumechange
* @listens Technik #volumechange
* /
'Volumenänderung',
/**
* Wird ausgelöst, wenn der Texttrack geändert wurde
*
* @event Spieler #texttrackchange
* @Typ {Ereignis}
* /
/**
* Das `texttrackchange`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @privat
* @method Spieler #handleTechTexttrackchange_
* @fires Spieler #texttrackchange
* @listens Technik #texttrackchange
* /
'Texttrack-Änderung'
];
//Ereignisse, die in die Warteschlange gestellt werden, wenn die Wiedergabegeschwindigkeit Null ist
//Dies ist ein Hash für den alleinigen Zweck der Zuordnung von Ereignisnamen ohne Kamele
//zu Funktionsnamen in Kamele
const TECH_EVENTS_QUEUE = {
kann spielen: 'Kann spielen',
kann durchspielen: 'Kann durchspielen',
spielend: 'Spielen',
gesucht: 'Gesucht'
};
const BREAKPOINT_ORDER = [
'winzig',
'klein',
'klein',
'mittel',
'groß',
'groß',
'riesig'
];
const BREAKPOINT_CLASSES = {};
//grep: vjs-layout-tiny
//grep: vjs-layout-x-small
//grep: vjs-layout-small
//grep: vjs-layout-medium
//grep: vjs-layout-large
//grep: vjs-layout-x-large
//grep: vjs-layout-huge
breakPoint_Order.forEach (k) => {
const v = k.charat (0) === 'x'? `x-$ {k.substring (1)} `: k;
BREAKPOINT_CLASSES [k] = `vjs-layout-$ {v} `;
});
const DEFAULT_BREAKPOINTS = {
winzig: 210,
klein: 320,
klein: 425,
mittel: 768,
groß: 1440,
xgroß: 2560,
riesig: Unendlichkeit
};
/**
* Eine Instanz der Klasse `Player` wird erstellt, wenn eine der Methoden von Video.js eingerichtet wird
* werden verwendet, um ein Video zu initialisieren.
*
* Nachdem eine Instanz erstellt wurde, kann auf zwei Arten global darauf zugegriffen werden:
* 1. Durch das Aufrufen von `videojs ('example_video_1'); `
* 2. Indem du es direkt über `videojs.players.example_video_1; `benutzt
*
* @erweitert Komponente
* /
class Player erweitert Komponente {
/**
* Erstellen Sie eine Instanz dieser Klasse.
*
* @param {Element} tag
* Das ursprüngliche Video-DOM-Element, das für die Konfiguration von Optionen verwendet wurde.
*
* @param {Object} [Optionen]
* Objekt der Optionsnamen und -werte.
*
* @param {Component~ReadyCallback} [ready]
* Bereite Rückruffunktion.
* /
Konstruktor (Tag, Optionen, bereit) {
//Stellen Sie sicher, dass die Tag-ID existiert
tag.id = tag.id || options.id || `vjs_video_$ {guid.newGUID ()} `;
//Optionen festlegen
//Das Optionsargument überschreibt die im Video-Tag gesetzten Optionen
//was global gesetzte Optionen überschreibt.
//Dieser letzte Teil stimmt mit der Ladereihenfolge überein
//(Tag muss vor Player existieren)
Optionen = assign (player.getTagSettings (Tag), Optionen);
//Verzögern Sie die Initialisierung von Kindern, weil wir etwas einrichten müssen
//Spielereigenschaften zuerst und kann `this` nicht vor `super () `verwenden
options.initChildren = falsch;
//Das Gleiche gilt für das Erstellen des Elements
options.createEl = falsch;
//Mischt das Event-Mixing nicht automatisch
options.evented = falsch;
//wir wollen nicht, dass der Spieler Berührungsaktivitäten an sich selbst meldet
//siehe enableTouchActivity in der Komponente
options.reportTouchActivity = false;
//Wenn die Sprache nicht gesetzt ist, hol dir das nächstgelegene lang-Attribut
wenn (! optionen.sprache) {
if (typeof tag.closest === 'Funktion') {
const closest = tag.closest ('[lang]');
if (close && closest.getAttribute) {
options.language = closest.getAttribute ('lang');
}
} sonst {
sei Element = Tag;
während (element && element.nodeType === 1) {
wenn (dom.getAttributes (element) .hasOwnProperty ('lang')) {
options.language = element.getAttribute ('lang');
pause;
}
element = element.ParentNode;
}
}
}
//Initialisierung der Basiskomponente mit neuen Optionen ausführen
super(null, options, ready);
//Erstelle gebundene Methoden für Dokument-Listener.
this.boundDocumentFullScreenChange_ = (e) => this.documentFullScreenChange_ (e);
this.boundFullWindowOnescKey_ = (e) => this.fullWindowOnescKey (e);
this.boundUpdateStyleel_ = (e) => this.updateStyleL_ (e);
this.boundApplyInitTime_ = (e) => this.applyInitTime_ (e);
this.boundUpdateCurrentBreakPoint_ = (e) => this.updateCurrentBreakPoint_ (e);
this.boundHandleTechClick_ = (e) => this.handleTechClick_ (e);
this.boundHandletechDoubleClick_ = (e) => this.handletechDoubleClick_ (e);
this.boundHandletechTouchStart_ = (e) => this.handletechTouchStart_ (e);
this.boundHandletechTouchMove_ = (e) => this.handletechTouchMove_ (e);
this.boundHandletechTouchEnd_ = (e) => this.handletechTouchEnd_ (e);
this.boundHandleTechTap_ = (e) => this.HandletTechTap_ (e);
//Die Standardeinstellung ist FullScreen_ auf false
this.isFullScreen_ = falsch;
//Logger erstellen
this.log = createLogger (this.id_);
//Behalte unseren eigenen Verweis auf die Vollbild-API, damit sie in Tests verspottet werden kann
this.fsApi_ = VollbildAPI;
//Verfolgt, wann ein Techniker das Poster ändert
this.isPosterFromTech_ = false;
//Enthält Rückrufinformationen, die in die Warteschlange gestellt werden, wenn die Wiedergabegeschwindigkeit Null ist
//und eine Suche findet statt
this.queuedCallbacks_ = [];
// Schalten Sie den API-Zugriff aus, da wir eine neue Technologie laden, die möglicherweise asynchron geladen wird
this.isReady_ = false;
//Initialstatus HasStarted_
this.hasStarted_ = false;
//Initialisiert den Status UserActive_
this.userActive_ = falsch;
//DebugEnabled_ initiieren
this.debugEnabled_ = false;
//Initialstatus AudioOnlyMode_
this.AudioOnlyMode_ = falsch;
//Initialstatus AudioPosterMode_
this.AudioPosterMode_ = falsch;
//Initialstatus AudioOnlyCache_
this.audioOnlyCache_ = {
Spielerhöhe: null,
Versteckte Kinder: []
};
//wenn das globale Optionsobjekt versehentlich weggeblasen wurde von
//jemand, mit einem informativen Fehler vorzeitig aussteigen
wenn (! diese.optionen_ |
! this.options_.TechOrder ||
! this.options_.techOrder.length) {
löst einen neuen Fehler aus ('Es wurde kein TechOrder angegeben. Hast du '+ überschrieben?
'videojs.options statt nur das '+ zu ändern
„Eigenschaften, die Sie überschreiben möchten? ');
}
//Speichert das ursprüngliche Tag, das zum Festlegen von Optionen verwendet wurde
this.tag = Tag;
//Speichert die Tag-Attribute, die zum Wiederherstellen des HTML5-Elements verwendet wurden
this.tagAttributes = tag && dom.getAttributes (Tag);
//Aktuelle Sprache aktualisieren
this.language (this.options_.language);
//Unterstützte Sprachen aktualisieren
wenn (Options.Sprachen) {
//Normalisiere die Sprachen der Player-Optionen auf Kleinbuchstaben
const languageStoLower = {};
object.getOwnPropertyNames (options.languages) .forEach (Funktion (Name) {
languageToLower [name.toLowerCase ()] = optionen.languages [Name];
});
this.languages_ = Sprachen, die es zu senken gilt;
} sonst {
this.languages_ = player.prototype.options_.languages;
}
this.resetCache_();
//Plakat setzen
this.poster_ = optionen.poster || „;
//Steuerung einstellen
this.controls_ =!! Optionen. Steuerelemente;
//Ursprüngliche Tag-Einstellungen werden in den Optionen gespeichert
//jetzt sofort entfernen, damit die nativen Steuerelemente nicht blinken.
//Kann von der HTML5-Technologie wieder aktiviert werden, wenn NativeControlsForTouch wahr ist
tag.controls = falsch;
tag.removeAttribute ('Kontrollen');
this.changingSrc_ = false;
this.playCallbacks_ = [];
this.playTerminatedQueue_ = [];
//das Attribut überschreibt die Option
wenn (tag.hasAttribute ('Autoplay')) {
this.autoplay (wahr);
} sonst {
//andernfalls verwende den Setter zur Validierung und
//setze den richtigen Wert.
this.autoplay (this.options_.autoplay);
}
//Plugins überprüfen
if (options.plugins) {
Object.keys(options.plugins).forEach((name) => {
if (tippe diesen [Name] ein! == 'Funktion') {
einen neuen Fehler auslösen (`Plugin „$ {name}“ existiert nicht`);
}
});
}
/*
* Speichern Sie den internen Zustand des Schrubbens
*
* @privat
* @return {Boolean} Wahr, wenn der Benutzer scrubbt
* /
this.scrubbing_ = falsch;
this.el_ = this.createEl();
//Mache daraus ein Event-Objekt und verwende `el_` als Event-Bus.
evented (this, {eventBusKey: 'el_'});
//Hör dir die FullscreenChange-Handler von Document und Player an, damit wir diese Ereignisse erhalten
//bevor ein Benutzer sie erhalten kann, damit wir isFullScreen entsprechend aktualisieren können.
//stellen Sie sicher, dass wir uns die Fullscreenchange-Ereignisse vor allem anderen anhören, um sicherzustellen, dass
//Unsere isFullScreen-Methode wird sowohl für interne als auch für externe Komponenten ordnungsgemäß aktualisiert.
if (this.fsApi_.requestFullscreen) {
events.on (Dokument, this.fsapi_.fullScreenChange, this.boundDocumentFullScreenChange_);
this.on (this.fsapi_.fullScreenChange, this.boundDocumentFullScreenChange_);
}
wenn (this.fluid_) {
this.on(['playerreset', 'resize'], this.boundUpdateStyleEl_);
}
//Wir wollen auch die ursprünglichen Player-Optionen an jede Komponente und jedes Plugin weitergeben
//auch, damit sie später nicht erneut in den Player greifen müssen, um Optionen zu erhalten.
//Wir müssen auch eine weitere Kopie von this.options_ erstellen, damit wir nicht mit
//eine unendliche Schleife.
const playerOptionsCopy = mergeOptions (this.options_);
//Plugins laden
if (options.plugins) {
Object.keys(options.plugins).forEach((name) => {
this [Name] (options.plugins [Name]);
});
}
//Aktiviere den Debug-Modus, um das Debugon-Ereignis für alle Plugins auszulösen.
wenn (options.debug) {
this.debug (wahr);
}
this.options_.playerOptions = PlayerOptionsCopy;
this.middleware_ = [];
this.PlaybackRates (Optionen.PlaybackRates);
this.initChildren();
//Setze isAudio basierend darauf, ob ein Audio-Tag verwendet wurde oder nicht
this.isAudio (tag.nodeName.toLowerCase () === 'audio');
//Aktualisiere die Steuerelemente ClassName. Dies ist nicht möglich, wenn die Steuerung anfänglich aktiviert ist
//gesetzt, weil das Element noch nicht existiert.
wenn (this.controls ()) {
this.addClass('vjs-controls-enabled');
} sonst {
this.addClass('vjs-controls-disabled');
}
//Lege das ARIA-Label und die Regionsrolle je nach Spielertyp fest
this.el_.setAttribute ('Rolle', 'Region');
if (this.isAudio()) {
this.el_.setAttribute ('aria-label', this.localize ('Audioplayer'));
} sonst {
this.el_.setAttribute ('aria-label', this.localize ('Videoplayer'));
}
if (this.isAudio()) {
this.addClass ('vjs-audio');
}
wenn (this.flexNotSupported_ ()) {
this.addClass ('vjs-no-flex');
}
// TODO: Machen Sie das schlauer. Benutzerstatus zwischen Berühren/Mausklick umschalten
//Ereignisse verwenden, da Geräte sowohl Berührungs- als auch Mausereignisse haben können.
// TODO: Stellen Sie sicher, dass diese Überprüfung erneut ausgeführt wird, wenn das Fenster zwischen Monitoren wechselt
//(Siehe https://github.com/videojs/video.js/issues/5683)
wenn (browser.TOUCH_ENABLED) {
this.addClass ('vjs-touch-enabled');
}
//iOS Safari hat die Hover-Behandlung unterbrochen
wenn (! Browser.is_iOS) {
this.addClass ('vjs-workinghover');
}
//Mach den Spieler anhand seiner ID leicht auffindbar
player.players [this.id_] = das;
//Füge eine Hauptversionsklasse hinzu, um CSS in Plugins zu unterstützen
const majorVersion = version.split ('.') [0];
this.addClass (`vjs-v$ {majorVersion} `);
//Wenn der Player zum ersten Mal initialisiert wird, aktiviere Aktivität, also Komponenten
//wie die Kontrollleisten zeigen sich bei Bedarf
this.userActive(true);
this.reportUserActivity();
this.one ('play', (e) => this.listenForUserActivity_ (e));
this.on ('stageclick', (e) => this.handleStageClick_ (e));
this.on('keydown', (e) => this.handleKeyDown(e));
this.on ('languagechange', (e) => this.handleLanguageChange (e));
this.breakpoints (this.options_.breakpoints);
this.responsive (this.options_.responsive);
//Beide Audiomodusmethoden aufrufen, nachdem der Player vollständig ist
//Setup, um die von ihnen ausgelösten Ereignisse abhören zu können
this.on ('bereit', () => {
//Zuerst die Methode AudioPosterMode aufrufen, damit
//der AudioOnlyMode kann Vorrang haben, wenn beide Optionen auf true gesetzt sind
this.AudioPosterMode (this.options_.AudioPosterMode);
this.AudioOnlyMode (this.options_.AudioOnlyMode);
});
}
/**
* Zerstört den Videoplayer und führt alle notwendigen Aufräumarbeiten durch.
*
* Dies ist besonders hilfreich, wenn Sie Videos dynamisch hinzufügen und entfernen
* zum/vom DOM.
*
* @fires Spieler #dispose
* /
dispose() {
/**
* Wird aufgerufen, wenn der Spieler entsorgt wird.
*
* @event Spieler #dispose
* @Typ {EventTarget~Event}
* /
this.trigger('dispose');
//verhindere, dass dispose zweimal aufgerufen wird
this.off ('entsorgen');
//Vergewissere dich, dass alle spielerspezifischen Dokumentenzuhörer ungebunden sind. Das ist
events.OFF (Dokument, this.fsapi_.fullScreenChange, this.boundDocumentFullScreenChange_);
Events.off(document, 'keydown', this.boundFullWindowOnEscKey_);
wenn (this.styleEL_ && this.styleEL_.parentNode) {
this.styleEL_.parentNode.removeChild (this.styleEL_);
this.styleEL_ = null;
}
//Verweis auf diesen Spieler töten
player.players [this.id_] = null;
wenn (this.tag && this.tag.player) {
this.tag.player = null;
}
wenn (this.el_ && this.el_.player) {
this.el_.player = null;
}
if (this.tech_) {
this.tech_.dispose();
this.isPosterFromTech_ = false;
this.poster_ = '';
}
wenn (this.playerELINGEST_) {
this.playerELINGEST_ = null;
}
if (this.tag) {
this.tag = null;
}
Middleware.clearcacheForPlayer (this);
//entferne alle Event-Handler für Tracklisten
//alle Tracks und Track-Listener werden entfernt am
//technische Entsorgung
TRACK_TYPES.names.forEach((name) => {
const props = TRACK_TYPES[name];
const list = this [props.getterName] ();
//wenn es keine native Liste ist
//wir müssen die Event-Listener manuell entfernen
wenn (list && list.off) {
list.off ();
}
});
//das eigentliche .el_ wird hier entfernt oder ersetzt, wenn
super.dispose ({restoReel: this.options_.restoReel});
}
/**
* Erstelle das DOM-Element des `Player`.
*
* @return {Element}
* Das DOM-Element, das erstellt wird.
* /
createEl() {
sei tag = this.tag;
lass es sein;
lass playerelingest = this.playerelingest_ = tag.parentNode && tag.parentNode.hasAttribute && tag.parentNode.hasAttribute ('data-vjs-player');
const divEmbed = this.tag.tagName.toLowerCase () === 'video-js';
wenn (playerRelingest) {
el = this.el_ = Tag.parentNode;
} sonst wenn (! Dive Embed) {
el = this.el_ = super.createEl ('div');
}
//Kopiere alle Attribute aus dem Tag, einschließlich ID und Klasse
//Die ID bezieht sich jetzt auf die Player-Box, nicht auf das Video-Tag
const attrs = dom.getAttributes (Tag);
wenn (divEmbed) {
el = this.el_ = Tag;
tag = this.tag = document.createElement ('video');
während (el.children.length) {
tag.appendChild (el.FirstChild);
}
wenn (! dom.hasClass (de, 'video-js') {
dom.addClass (de, 'video-js');
}
el.appendChild (Schlagwort);
playerElingest = this.playerelingest_ = el;
//Eigenschaften aus unserem benutzerdefinierten `video-js`-Element verschieben
//zu unserem neuen `Video`-Element. Das wird Dinge bewegen wie
//`src` oder `controls`, die vor dem Player über js gesetzt wurden
//wurde initialisiert.
object.keys (de) .forEach (k) => {
versuche {
tag [k] = el [k];
} catch (e) {
//wir haben eine Eigenschaft wie outerHTML, die wir nicht wirklich kopieren können, ignoriere sie
}
});
}
//setze tabindex auf -1, um das Videoelement aus der Fokusreihenfolge zu entfernen
tag.setAttribute ('tabindex', '-1');
attrs.tabindex = '-1';
//Problemumgehung für #4583 (JAWS+IE kündigt weder BPB noch Play-Button an) und
//für das gleiche Problem mit Chrome (unter Windows) mit JAWS.
//Siehe https://github.com/FreedomScientific/VFO-standards-support/issues/78
//Beachten Sie, dass wir nicht erkennen können, ob JAWS verwendet wird, sondern dieses ARIA-Attribut
//ändert das Verhalten von IE11 oder Chrome nicht, wenn JAWS nicht verwendet wird
wenn (IE_VERSION | (IS_CHROME & IS_WINDOWS)) {
tag.setAttribute ('Rolle', 'Anwendung');
attrs.role = 'Anwendung';
}
//Entferne die Breite/Höhen-Attribute aus dem Tag, damit CSS es zu 100% Breite/Höhe machen kann
tag.removeAttribute ('Breite');
tag.removeAttribute ('Höhe');
if ('Breite' in Buchstaben) {
lösche attrs.width;
}
if ('Höhe' in Zeichen) {
lösche attrs.height;
}
object.getOwnPropertyNames (attrs) .forEach (function (attr) {
//kopiere das Klassenattribut nicht in das Player-Element, wenn wir uns in einer div-Einbettung befinden
//Die Klasse ist im DivEmbed-Fall bereits richtig eingerichtet
//und wir wollen sicherstellen, dass die Klasse `video-js` nicht verloren geht
wenn (! (divEmbed && attr === 'Klasse') {
el.setAttribute (attr, attrs [attr]);
}
wenn (divEmbed) {
tag.setAttribute (attr, attrs [attr]);
}
});
//Tag-ID/Klasse für die Verwendung als HTML5-Wiedergabetechnologie aktualisieren
//Ich denke vielleicht, wir sollten das nach dem Einbetten in den Container tun, also die Klasse .vjs-tech
//blinkt nicht zu 100% Breite/Höhe, aber die Klasse gilt nur für das übergeordnete Objekt .video-js
tag.playerId = tag.id;
tag.id += '_html5_api';
tag.className = 'vjs-tech';
//Spieler auf Elementen auffindbar machen
tag.player = el.player = das;
//Der Standardstatus des Videos ist angehalten
this.addClass('vjs-paused');
//Füge ein Style-Element im Player hinzu, mit dem wir die Breite/Höhe festlegen
//des Players auf eine Weise, die immer noch durch CSS überschrieben werden kann, genau wie der
//Videoelement
wenn (window.videoJS_NO_DYNAMIC_STYLE! == wahr) {
this.styleEl_ = styleSheet.createStyleElement ('vjs-styles-dimensions');
const defaultsStyleEl = Dom.$ ('.vjs-styles-defaults');
const head = Dom.$('head');
head.insertBefore (this.styleEL_, defaultsStyleEL? defaultsStyleEl.NextSibling: head.FirstChild);
}
this.fill_ = falsch;
this.fluid_ = falsch;
//Übergeben Sie die Optionen width/height/aspectRatio, die den Stil el aktualisieren
this.width (this.options_.width);
this.height (this.options_.height);
this.fill (this.options_.fill);
this.fluid (this.options_.fluid);
this.AspectRatio (this.Options_.AspectRatio);
//unterstützt sowohl CrossOrigin als auch Crossorigin, um Verwirrung und Probleme rund um den Namen zu vermeiden
this.crossOrigin (this.options_.crossOrigin || this.options_.crossOrigin);
//Verstecke alle Links innerhalb des Video-/Audio-Tags,
//weil IE sie nicht vollständig vor Screenreadern versteckt.
const links = tag.getElementsByTagName ('a');
für (sei i = 0; i < links.length; i++) {
const linkEL = links.item (i);
dom.addClass (LinkEl, 'vjs-hidden');
linkel.setAttribute ('versteckt', 'versteckt');
}
//insertElFirst scheint den NetworkState von 3 auf 2 flackern zu lassen, also
//Behalte das Original für später im Auge, damit wir wissen, ob die Quelle ursprünglich ausgefallen ist
tag.initNetworkState_ = Tag.NetworkState;
//Wickeln Sie das Videotag in den Container div (el/box)
wenn (Tag.parentNode &&! Spieler Elingest) {
tag.parentNode.insertBefore (el, tag);
}
//füge das Tag als erstes untergeordnetes Element des Player-Elements ein
//dann füge es manuell zum Children-Array hinzu, sodass this.addChild
//funktioniert einwandfrei für andere Komponenten
// //
//Das iPhone ist kaputt, das wurde im HTML5-Setup behoben.
dom.prependTo (tag, el);
this.children_.unshift (Tag);
//Setze lang attr auf Player, um sicherzustellen, dass css:lang () mit dem Player übereinstimmt
//wenn es auf etwas anderes als das Dokument eingestellt wurde
this.el_.setAttribute ('lang', this.language_);
this.el_.setAttribute ('translate', 'nein');
this.el_ = el;
zurück el;
}
/**
* Ruft die CrossOrigin-Option des `Player` ab oder legt sie fest. Für den HTML5-Player bedeutet dies
* setzt die Eigenschaft "crossOrigin" auf den Tag "<video>", um den CORS zu steuern
* verhalten.
*
* @see [Video Element Attributes]{@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-crossorigin}
*
* @param {string} [Wert]
* Der Wert, auf den der CrossOrigin des `Player` gesetzt werden soll. Wenn ein Argument
* angegeben wird, muss eine der Optionen "anonymous" oder "use-credentials" sein.
*
* @return {string|undefined}
* - Der aktuelle CrossOrigin-Wert des `Player` beim Abrufen.
* - undefiniert bei der Einstellung
* /
CrossOrigin (Wert) {
if (!Wert) {
gib this.techGet_ ('crossOrigin') zurück;
}
wenn (Wert! == 'anonym' && Wert! == 'Anmeldeinformationen') {
log.warn (`crossOrigin muss „anonymous“ oder „use-credentials“ sein, vorausgesetzt „$ {value}“ `);
rückkehr;
}
this.techCall_ ('setCrossOrigin', Wert);
rückkehr;
}
/**
* Ein Getter/Setter für die Breite des `Player`. Gibt den konfigurierten Wert des Spielers zurück.
* Um die aktuelle Breite zu ermitteln, benutze `currentWidth () `.
*
* @param {Zahl} [Wert]
* Der Wert, auf den die Breite des `Player` eingestellt werden soll.
*
* @return {number}
* Die aktuelle Breite des `Player` beim Abrufen.
* /
Breite (Wert) {
gib this.dimension ('Breite', Wert) zurück;
}
/**
* Ein Getter/Setter für die Größe des `Spieler`. Gibt den konfigurierten Wert des Spielers zurück.
* Um die aktuelle Höhe zu ermitteln, verwende `currenttheight () `.
*
* @param {Zahl} [Wert]
* Der Wert, auf den die Größe des `Player` eingestellt werden soll.
*
* @return {number}
* Die aktuelle Höhe des `Player` beim Abrufen.
* /
Höhe (Wert) {
gib this.dimension ('Höhe', Wert) zurück;
}
/**
* Ein Getter/Setter für die Breite und Höhe des `Player`.
*
* Abmessung @param {string}
* Diese Zeichenfolge kann sein:
* - 'Breite'
* - 'Höhe'
*
* @param {Zahl} [Wert]
* Wert für die im ersten Argument angegebene Dimension.
*
* @return {number}
* Der Wert der Dimensionsargumente beim Abrufen von (Breite/Höhe).
* /
Dimension (Dimension, Wert) {
const privDimension = Abmessung + '_';
if (Wert === undefiniert) {
gib das zurück [PrivDimension] || 0;
}
if (Wert === "|| Wert === 'auto') {
//Wenn eine leere Zeichenfolge angegeben wird, setzen Sie die Dimension auf automatisch zurück
this [PrivDimension] = undefiniert;
this.updateStyleEl_();
rückkehr;
}
const parsedVal = parseFloat (Wert);
wenn (isNaN (parsedVal)) {
log.error (`Ungültiger Wert „$ {value}“ angegeben für $ {dimension} `);
rückkehr;
}
diese [PrivDimension] = parsedVal;
this.updateStyleEl_();
}
/**
* Ein Getter/Setter/Toggler für das vjs-fluid `className` auf dem `Player`.
*
* Wenn Sie diese Option einschalten, wird der Füllmodus deaktiviert.
*
* @param {boolean} [bool]
* - Bei einem Wert von true wird die Klasse hinzugefügt.
* - Bei einem Wert von false wird die Klasse entfernt.
* - Kein Wert wird ein Getter sein.
*
* @return {boolean|undefined}
* - Der Wert der Flüssigkeit bei der Beschaffung.
* - bei der Einstellung "unbestimmt".
* /
flüssig (bool) {
if (bool === undefiniert) {
kehre zurück!! diese.flüssigkeit_;
}
this.fluid_ =!! boolen;
if (isEvented(this)) {
this.off (['playerreset', 'Größe ändern'], this.boundUpdateStyleel_);
}
if (bool) {
this.addClass ('vjs-fluid');
this.fill (falsch);
addEventedCallback (this, () => {
this.on(['playerreset', 'resize'], this.boundUpdateStyleEl_);
});
} sonst {
this.removeClass ('vjs-fluid');
}
this.updateStyleEl_();
}
/**
* Ein Getter/Setter/Toggler für das vjs-fill `className` auf dem `Player`.
*
* Wenn Sie diese Option einschalten, wird der Flüssigkeitsmodus ausgeschaltet.
*
* @param {boolean} [bool]
* - Bei einem Wert von true wird die Klasse hinzugefügt.
* - Bei einem Wert von false wird die Klasse entfernt.
* - Kein Wert wird ein Getter sein.
*
* @return {boolean|undefined}
* - Der Wert der Flüssigkeit bei der Beschaffung.
* - bei der Einstellung "unbestimmt".
* /
fill (bool) {
if (bool === undefiniert) {
kehre zurück!! dieses.fill_;
}
this.fill_ =!! boolen;
if (bool) {
this.addClass ('vjs-fill');
this.fluid (falsch);
} sonst {
this.removeClass ('vjs-fill');
}
}
/**
* Seitenverhältnis abrufen/einstellen
*
* @param {string} [Verhältnis]
* Seitenverhältnis für den Spieler
*
* @return {string|undefined}
* gibt das aktuelle Seitenverhältnis beim Abrufen zurück
* /
/**
* Ein Getter/Setter für das Seitenverhältnis des `Player`.
*
* @param {string} [Verhältnis]
* Der Wert, auf den das Seitenverhältnis des `Player` eingestellt werden soll.
*
* @return {string|undefined}
* - Das aktuelle Seitenverhältnis des `Player` beim Abrufen.
* - undefiniert bei der Einstellung
* /
Seitenverhältnis (Verhältnis) {
if (Verhältnis === undefiniert) {
gib this.AspectRatio_ zurück;
}
//Prüfe das Format Width:Height
wenn (! (/^\ d+\:\ d+$/) .test (Verhältnis)) {
löst einen neuen Fehler aus ('Falscher Wert für das Seitenverhältnis angegeben. Das Format sollte breit:höhe sein, zum Beispiel 16:9. ');
}
this.AspectRatio_ = Verhältnis;
//Wir gehen davon aus, dass du, wenn du ein Seitenverhältnis einstellst, den Fluidmodus verwenden möchtest,
//weil du im festen Modus Breite und Höhe selbst berechnen könntest.
this.fluid (wahr);
this.updateStyleEl_();
}
/**
* Aktualisiere die Stile des `Player`-Elements (Höhe, Breite und Seitenverhältnis).
*
* @privat
* @listens Tech#loadedmetadata
* /
updateStyleL_ () {
wenn (window.videoJS_NO_DYNAMIC_STYLE === wahr) {
const width = typeofthis.width_ === 'Zahl'? this.width_: this.options_.width;
const height = typeofthis.height_ === 'Zahl'? this.height_: this.options_.height;
const techEL = this.tech_ && this.tech_.el ();
wenn (TechEL) {
wenn (Breite >= 0) {
techEL.Width = Breite;
}
wenn (Höhe >= 0) {
techEL.Height = Höhe;
}
}
rückkehr;
}
Breite links;
Höhe des Fahrzeuges;
lass AspecRatio;
lass IDClass;
//Das Seitenverhältnis wird entweder direkt oder zur Berechnung von Breite und Höhe verwendet.
wenn (this.AspectRatio_! = undefiniert & this.AspectRatio_! == 'automatisch') {
//Verwende ein beliebiges AspectRatio, das speziell festgelegt wurde
AspectRatio = this.AspectRatio_;
} sonst wenn (this.videoWidth () > 0) {
//Andernfalls versuche das Seitenverhältnis aus den Video-Metadaten zu ermitteln
AspectRatio = this.videoWidth () + ':' + this.videoHeight ();
} sonst {
//Oder verwende eine Standardeinstellung. Das Videoelement ist 2:1, aber 16:9 ist üblicher.
Seitenverhältnis = '16:9';
}
//Holen Sie sich das Verhältnis als Dezimalzahl, mit der wir Dimensionen berechnen können
const RatioParts = Seitenverhältnis.split (':');
const ratioMultiplier = Verhältnis Teile [1]/Verhältnis Teile [0];
wenn (this.width_! == undefiniert) {
//Benutze jede Breite, die speziell festgelegt wurde
breite = this.width_;
} sonst wenn (this.height_! == undefiniert) {
//Oder berechne die Breite aus dem Seitenverhältnis, falls eine Höhe eingestellt wurde
width = this.height_/ratioMultiplier;
} sonst {
//Oder verwende die Metadaten des Videos oder verwende die Standardeinstellung des Video-El von 300
breite = this.videoWidth () || 300;
}
wenn (this.height_! == undefiniert) {
//Verwenden Sie eine beliebige Höhe, die speziell festgelegt wurde
Höhe = this.height_;
} sonst {
//Andernfalls berechne die Höhe aus dem Verhältnis und der Breite
Höhe = Breite * RatioMultiplier;
}
//Stellen Sie sicher, dass die CSS-Klasse gültig ist, indem Sie mit einem Alpha-Zeichen beginnen
wenn (/^ [^a-Za-Z]/) .test (this.id ())) {
idClass = 'Dimensionen-' + this.id ();
} sonst {
idClass = this.id () + '-Dimensionen';
}
//Stelle sicher, dass immer noch die richtige Klasse für das Style-Element auf dem Player ist
this.addClass (IDClass);
styleSheet.setTextContent (this.styleEL_, `
. $ {idClass} {
Breite: $ {width} px;
Höhe: $ {height} px;
}
. $ {idClass} .vjs-fluid:nicht (.vjs-Nur-Audio-Modus) {
obere Polsterung: $ {ratioMultiplier * 100}%;
}
`);
}
/**
* Laden/Erstellen Sie eine Instanz von playback {@link Tech} inklusive Element
* und API-Methoden. Hängen Sie dann als Kind das `Tech`-Element in `Player` an.
*
* @param {string} TechName
* Name der Wiedergabe-Technologie
*
* @param {string} Quelle
* Videoquelle
*
* @privat
* /
LoadTech_ (TechName, Quelle) {
//Aktuelle Wiedergabe-Technologie anhalten und entfernen
if (this.tech_) {
Das.unloadTech_ ();
}
const titleTechName = toTitleCase (TechName);
const camelTechName = techname.charat (0) .toLowerCase () + techname.Slice (1);
//entferne das HTML5-Video-Tag, sobald wir eine andere Technologie verwenden
if (Titel/Techname! == 'Html5' && this.tag) {
tech.getTech ('Html5') .disposeMediaElement (this.tag);
this.tag.player = null;
this.tag = null;
}
this.techName_ = TitelTechName;
// Schalten Sie den API-Zugriff aus, da wir eine neue Technologie laden, die möglicherweise asynchron geladen wird
this.isReady_ = false;
sei autoplay = this.autoplay ();
//wenn Autoplay eine Zeichenfolge ist (oder `true` mit normalizeAutoplay: true) geben wir false an den Techniker weiter
//weil der Player das Autoplay bei `loadstart` übernehmen wird
if (typeof this.autoplay () === 'string' || this.autoplay () === true && this.options_.normalizeAutoplay) {
Autoplay = falsch;
}
//Schnapp dir technologiespezifische Optionen aus den Player-Optionen und füge Quelle und übergeordnetes Element hinzu, um sie zu verwenden.
const techOptions = {
Quelle,
automatisches Abspielen,
'Native Controls for Touch': this.options_.NativeControlsForTouch,
'playerID': this.id (),
'techID': `$ {this.id ()} _$ {camelTechName} _api`,
'playsinline': this.options_.playsinline,
'vorladen': this.options_.preload,
'Schleife': this.options_.loop,
'PictureInPicture': this.options_.DisablePictureInPicture,
'stumm': this.options_.muted,
'Poster': this.poster (),
'Sprache': this.language (),
'playerELINGEST': this.playerELINGEST_ || falsch,
'vtt.js': this.options_ ['vtt.js'],
'Poster überschreiben kann':!! this.options_.tech kann Poster überschreiben,
'enableSourceSet': this.options_.enableSourceSet,
'Versprechen': this.options_.promise
};
TRACK_TYPES.names.forEach((name) => {
const props = TRACK_TYPES[name];
techOptions [props.getterName] = dieser [props.PrivateName];
});
assign (techOptions, this.options_ [TitleTechName]);
assign (techOptions, this.options_ [CamelTechName]);
assign (techOptions, this.options_ [Techname.toLowerCase ()]);
if (this.tag) {
techOptions.tag = diese.tag;
}
if (source && source.src === this.cache_.src && this.cache_.currentTime > 0) {
techOptions.startTime = this.Cache_.CurrentTime;
}
//Technologie-Instanz initialisieren
const techClass = tech.getTech (TechName);
wenn (! TechClass) {
einen neuen Fehler auslösen (`Es ist kein Techniker mit dem Namen '$ {titleTechName} 'vorhanden! '$ {titleTechName} 'sollte mit VideoJS.registerTech () registriert werden '`);
}
this.tech_ = neue TechClass (TechOptions);
//Player.triggerReady ist immer asynchron, also muss das nicht asynchron sein
this.tech_.ready (fn.Bind (this, this.handletechReady_), wahr);
textTrackConverter.jsonToTextTracks (this.textTracksJSON_ || [], this.tech_);
//Höre dir alle HTML5-definierten Ereignisse an und löse sie auf dem Player aus
tech_events_retrigger.forEach (Ereignis) => {
this.on (this.tech_, event, (e) => this [`handleTech$ {toTitleCase (event)} _`] (e));
});
object.keys (TECH_EVENTS_QUEUE) .forEach ((Ereignis) => {
this.on (this.tech_, ereignis, (EventObj) => {
if (this.tech_.playbackRate () === 0 && this.tech_.seeking ()) {
this.queuedCallbacks_.push ({
Rückruf: this [`handleTech$ {TECH_EVENTS_QUEUE [event]} _`] .bind (this),
Veranstaltung: EventObj
});
rückkehr;
}
this [`handleTech$ {TECH_EVENTS_QUEUE [event]} _`] (eventObj);
});
});
this.on (this.tech_, 'loadstart', (e) => this.handleTechLoadStart_ (e));
this.on (this.tech_, 'sourceset', (e) => this.handleTechSourceSet_ (e));
this.on (this.tech_, 'waiting', (e) => this.handletechWaiting_ (e));
this.on (this.tech_, 'beendet', (e) => this.handletTechEnded_ (e));
this.on (this.tech_, 'suche', (e) => this.handleTechSeeking_ (e));
this.on (this.tech_, 'play', (e) => this.handleTechPlay_ (e));
this.on (this.tech_, 'firstplay', (e) => this.handletechFirstPlay_ (e));
this.on (this.tech_, 'pause', (e) => this.handleTechPause_ (e));
this.on (this.tech_, 'durationchange', (e) => this.handleTechDurationChange_ (e));
this.on (this.tech_, 'fullscreenchange', (e, data) => this.handleTechFullScreenChange_ (e, Daten));
this.on (this.tech_, 'fullscreenerror', (e, err) => this.handleTechFullScreenError_ (e, Fehler));
this.on (this.tech_, 'enterpictureinpicture', (e) => this.handleTechenterPicturePicture_ (e));
this.on (this.tech_, 'leavePictureInPicture', (e) => this.handleTechLeavePictureInPicture_ (e));
this.on (this.tech_, 'Fehler', (e) => this.handletechError_ (e));
this.on (this.tech_, 'posterchange', (e) => this.handleTechPosterChange_ (e));
this.on (this.tech_, 'textdata', (e) => this.handleTechTextData_ (e));
this.on (this.tech_, 'ratechange', (e) => this.handletechrateChange_ (e));
this.on (this.tech_, 'geladene Metadaten', this.boundUpdateStyleel_);
this.usingNativeControls (this.techGet_ ('Kontrollen'));
if (this.controls () &&! this.using NativeControls ()) {
this.addTechControlsListeners_();
}
//Füge das Tech-Element im DOM hinzu, falls es nicht schon da war
//Achte darauf, dass du nicht das originale Videoelement einfügst, wenn du Html5 verwendest
wenn (this.tech_.el () .parentNode! == this.el () && (titleTechname! == 'Html5' |! diese.tag)) {
dom.prependTo (this.tech_.el (), this.el ());
}
//Entferne die ursprüngliche Video-Tag-Referenz, nachdem die erste Technologie geladen wurde
if (this.tag) {
this.tag.player = null;
this.tag = null;
}
}
/**
* Entlade und entsorge die aktuelle Wiedergabe {@link Tech}.
*
* @privat
* /
unloadTech_ () {
//Speichere die aktuellen Textspuren, damit wir dieselben Textspuren mit der nächsten Technologie wiederverwenden können
TRACK_TYPES.names.forEach((name) => {
const props = TRACK_TYPES[name];
this [props.privateName] = dieser [props.getterName] ();
});
this.textTracksJson_ = textTrackConverter.textTracksToJSON (this.tech_);
this.isReady_ = false;
this.tech_.dispose();
this.tech_ = falsch;
wenn (this.isPosterFromTech_) {
this.poster_ = '';
this.trigger('posterchange');
}
this.isPosterFromTech_ = false;
}
/**
* Gibt einen Verweis auf die aktuelle {@link Tech} zurück.
* Es wird standardmäßig eine Warnung vor der Gefahr einer direkten Nutzung der Technologie gedruckt
* aber jedes Argument, das angegeben wird, bringt die Warnung zum Schweigen.
*
* @param {*} [Sicherheit]
* Alles wurde weitergegeben, um die Warnung zum Schweigen zu bringen
*
* @return {Technik}
* Die Technologie
* /
Technik (Sicherheit) {
if (Sicherheit === undefiniert) {
log.warn ('Die Technologie direkt zu verwenden kann gefährlich sein. Ich hoffe du weißt, was du tust. \ n' +
„Weitere Informationen finden Sie unter https://github.com/videojs/video.js/issues/2617. \ n');
}
gib this.tech_ zurück;
}
/**
* Richten Sie Klick- und Touch-Listener für das Wiedergabeelement ein
*
* - Auf Desktops: Ein Klick auf das Video selbst schaltet die Wiedergabe um
* - Auf Mobilgeräten: Ein Klick auf das Video schaltet die Steuerung um
* was durch Umschalten des Benutzerstatus zwischen aktiv und
* inaktiv
* - Ein Tippen kann signalisieren, dass ein Benutzer aktiv oder inaktiv geworden ist
* z. B. ein kurzes Tippen auf einen iPhone-Film sollte die Bedienelemente anzeigen. Noch ein
* Durch schnelles Tippen sollten sie wieder ausgeblendet werden (signalisiert, dass der Benutzer inaktiv ist)
* Anzeigestatus)
* - Darüber hinaus möchten wir weiterhin, dass der Benutzer danach als inaktiv gilt
* ein paar Sekunden Inaktivität.
*
* > Hinweis: Der einzige Teil der iOS-Interaktion, den wir mit diesem Setup nicht nachahmen können
* zählt ein Berühren und Halten des Videoelements als Aktivität, um
* lassen Sie die Steuerelemente weiterhin anzeigen, aber das sollte kein Problem sein. Ein Berühren und Halten
* bei allen Steuerelementen bleibt der Benutzer weiterhin aktiv
*
* @privat
* /
Fügen Sie TechControlsListeners_ () {hinzu
//Achte darauf, alle vorherigen Listener zu entfernen, falls wir mehrmals angerufen werden.
this.removeTechControlsListeners_();
this.on (this.tech_, 'click', this.BoundHandleTechClick_);
this.on (this.tech_, 'dblclick', this.boundHandleTechDoubleClick_);
//Wenn die Steuerelemente ausgeblendet wären, wollen wir nicht, dass sich das ohne ein Tap-Event ändert
//also überprüfen wir, ob die Steuerelemente bereits angezeigt wurden, bevor wir den Benutzer melden
//Aktivität
this.on (this.tech_, 'touchstart', this.BoundHandleTechTouchStart_);
this.on (this.tech_, 'touchmove', this.boundHandleTechTouchMove_);
this.on (this.tech_, 'touchend', this.boundHandleTechTouchEnd_);
//Der Tap Listener muss hinter dem berührenden Zuhörer her kommen, weil der Tap
//Der Listener storniert jede ReportedUserActivity, wenn userActive gesetzt wird (false)
this.on (this.tech_, 'tap', this.boundHandleTechTap_);
}
/**
* Entferne die Listener, die für die Klick- und Tippsteuerung verwendet wurden. Das wird benötigt für
* Umschalten zu deaktivierten Steuerungen, bei denen ein Tippen/Berühren nichts bewirken sollte.
*
* @privat
* /
removeTechControlsListeners_ () {
//Wir wollen nicht einfach `this.off () `verwenden, weil vielleicht noch andere benötigt werden
//Zuhörer wurden von Technikern hinzugefügt, die dies erweitern.
this.off (this.tech_, 'tap', this.boundHandleTechTap_);
this.off (this.tech_, 'touchstart', this.BoundHandleTechTouchStart_);
this.off (this.tech_, 'touchmove', this.boundHandleTechTouchMove_);
this.off (this.tech_, 'touchend', this.boundHandleTechTouchEnd_);
this.off (this.tech_, 'click', this.BoundHandleTechClick_);
this.off (this.tech_, 'dblclick', this.boundHandleTechDoubleClick_);
}
/**
* Der Spieler wartet darauf, dass die Technologie bereit ist
*
* @privat
* /
handleTechReady_ () {
this.triggerReady();
//Behalte die gleiche Lautstärke wie zuvor
wenn (this.cache_.volume) {
this.techCall_ ('setVolume', this.cache_.volume);
}
//Schau, ob der Techniker beim Laden ein Poster mit höherer Auflösung gefunden hat
this.handleTechPosterChange_ ();
//Aktualisiere die Dauer, falls verfügbar
this.handleTechDurationChange_();
}
/**
* Das `loadstart`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen. Diese
* Die Funktion löst auch {@link Player #firstplay} aus, wenn es der erste Ladestart ist
* für ein Video.
*
* @fires Spieler #loadstart
* @Feuer Spieler#Erstes Spiel
* @listens Technik #loadstart
* @privat
* /
handleTechLoadStart_ () {
// TODO: Aktualisieren Sie, um stattdessen das Ereignis `emptied` zu verwenden. Siehe #1277.
this.removeClass('vjs-ended');
this.removeClass('vjs-seeking');
//setzt den Fehlerstatus zurück
this.error(null);
//Aktualisiere die Dauer
this.handleTechDurationChange_();
//Wenn es schon läuft, wollen wir jetzt ein Firstplay-Event auslösen.
//Das Firstplay-Event basiert sowohl auf den Play- als auch auf den Loadstart-Ereignissen
//was bei einer neuen Quelle in beliebiger Reihenfolge passieren kann
wenn (! this.pausiert ()) {
/**
* Wird ausgelöst, wenn der Benutzeragent anfängt, nach Mediendaten zu suchen
*
* @event Spieler #loadstart
* @Typ {EventTarget~Event}
* /
this.trigger('loadstart');
this.trigger('firstplay');
} sonst {
//setzt den HasStarted Status zurück
this.hasStarted (falsch);
this.trigger('loadstart');
}
//Autoplay erfolgt nach dem Ladestart für den Browser,
//also ahmen wir dieses Verhalten nach
this.manualAutoPlay_ (this.autoplay () === wahr & this.options_.normalizeAutoplay? 'abspielen': this.autoplay ());
}
/**
* Behandle Autoplay-Zeichenkettenwerte und nicht den typischen booleschen Wert
* Werte, mit denen sich der Techniker befassen sollte. Beachten Sie, dass dies nicht
* Teil jeder Spezifikation. Gültige Werte und was sie bewirken können
* gefunden auf dem Autoplay-Getter bei Player #autoplay ()
* /
ManualAutoPlay_ (Typ) {
wenn (! this.tech_ || Typ! == 'Zeichenfolge') {
rückkehr;
}
//Speichere den ursprünglichen Wert von muted (), setze muted auf true und versuche, () abzuspielen.
//Bei Ablehnung des Versprechens den gespeicherten Wert auf stummgeschaltet wiederherstellen
const resolveMuted = () => {
const previouslyMuted = this.muted ();
this.muted (wahr);
const restoreMuted = () => {
this.muted (zuvor stummgeschaltet);
};
//Bei Beendigung des Spiels stummgeschaltet wiederherstellen
this.playTerminatedQueue_.push (restoreMuted);
const mutedPromise = this.play ();
wenn (! isPromise (mutedPromise)) {
rückkehr;
}
gib mutedPromise.catch zurück (Fehler => {
RestoreMuted ();
gibt bei ManualAutoPlay einen neuen Fehler (`Rejection) aus. Wiederherstellung des gedämpften Werts. $ {Fehler? Fehler: „} `);
});
};
lass es versprechen;
//wenn stummgeschaltet standardmäßig auf true gesetzt ist
//das einzige was wir tun können ist Call Play
if (type === 'any' &&! this.muted ()) {
promise = this.play();
if (isPromise (versprechen)) {
promise = promise.catch (resolveMuted);
}
} sonst wenn (type === 'muted' &&! this.muted ()) {
versprechen = resolveMuted ();
} sonst {
promise = this.play();
}
wenn (! isPromise (Versprechen)) {
rückkehr;
}
Rückgabeversprechen.then () => {
this.trigger ({Typ: 'Autoplay-Erfolg', Autoplay: Typ});
}) .catch () => {
this.trigger ({Typ: 'Autoplay-Fehler', Autoplay: Typ});
});
}
/**
* Aktualisiere die internen Quellcaches, sodass wir die richtige Quelle von zurückgeben
* `src () `, `currentSource ()` und `currentSources () `.
*
* > Hinweis: `CurrentSources` wird nicht aktualisiert, wenn die übergebene Quelle existiert
* im aktuellen `CurrentSources`-Cache.
*
*
* @param {Tech~SourceObject} srcObj
* Eine Zeichenfolge oder Objektquelle, auf die unsere Caches aktualisiert werden sollen.
* /
updateSourceCaches_ (srcObj = „) {
sei src = srcoBJ;
sei der Typ = „;
if (Typ von src! == 'Zeichenfolge') {
src = srcoBj.src;
typ = srcobj.Type;
}
//stelle sicher, dass alle Caches auf Standardwerte gesetzt sind
//um eine Nullprüfung zu verhindern
this.cache_.source = this.cache_.source || {};
this.cache_.sources = this.cache_.sources || [];
//versuche den Typ des übergebenen src zu ermitteln
wenn (src &&! typ) {
type = findMimeType (this, src);
}
//aktualisiere den `CurrentSource`-Cache immer
this.cache_.source = mergeOptions ({}, srcObj, {src, type});
const matchingSources = this.cache_.sources.filter (s) => s.src && s.src === src);
const sourceElSources = [];
const sourceEls = this.$$ ('Quelle');
const matchingSourceEls = [];
für (sei i = 0; i < sourceELS.length; i++) {
const sourceObj = dom.getAttributes (sourceELs [i]);
Quelle elsources.push (Quelle Obj);
if (sourceObj.src && sourceObj.src === src) {
MatchingSourceels.push (Quellobj.src);
}
}
//wenn wir passende Quellen haben, aber keine passenden Quellen
//der aktuelle Quellcache ist nicht aktuell
if (matchingSourceEls.length &&! MatchingSources.length) {
this.cache_.sources = Quelle ELSources;
//wenn wir keine passende Quelle oder Quelle haben, setze den
//Quell-Cache zum `CurrentSource`-Cache
} sonst wenn (! MatchingSources.length) {
this.cache_.sources = [this.cache_.source];
}
//aktualisiere den Tech `src`-Cache
this.cache_.src = src;
}
/**
* *EXPERIMENTAL* Wird ausgelöst, wenn die Quelle auf dem {@link Tech} eingestellt oder geändert wird
* wodurch das Medienelement neu geladen wird.
*
* Es wird für die ursprüngliche Quelle und jede nachfolgende Quelle ausgelöst.
* Dieses Ereignis ist ein benutzerdefiniertes Ereignis von Video.js und wird vom {@link Tech} ausgelöst.
*
* Das Event-Objekt für dieses Ereignis enthält eine `src`-Eigenschaft, die die Quelle enthalten wird
* das war verfügbar, als das Ereignis ausgelöst wurde. Dies ist in der Regel nur erforderlich, wenn Video.js
* wechselt die Technik, während die Quelle geändert wurde.
*
* Es wird auch ausgelöst, wenn `load` auf dem Player (oder Medienelement) aufgerufen wird
* weil das {@link https://html.spec.whatwg.org/multipage/media.html#dom-media-load|specification für `load`}
* sagt, dass der Algorithmus zur Ressourcenauswahl abgebrochen und neu gestartet werden muss.
* In diesem Fall ist es sehr wahrscheinlich, dass die Eigenschaft `src` auf das gesetzt wird
* leere Zeichenfolge `""`, um anzuzeigen, dass wir nicht wissen, was die Quelle sein wird, aber
* dass es sich ändert.
*
* *Diese Veranstaltung ist derzeit noch experimentell und kann sich in kleineren Versionen ändern. *
* __Um dies zu verwenden, übergeben Sie dem Player die Option `enableSourceSet`. __
*
* @event Spieler #sourceset
* @Typ {EventTarget~Event}
* @prop {string} src
* Die Quell-URL, die verfügbar war, als das `sourceset` ausgelöst wurde.
* Es wird eine leere Zeichenfolge sein, wenn wir die Quelle nicht wissen können
* aber wisse, dass sich die Quelle ändern wird.
* /
/**
* Das `sourceset`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @fires Spieler #sourceset
* @listens Technik #sourceset
* @privat
* /
handleTechSourceSet_ (Ereignis) {
//aktualisiere den Quell-Cache nur, wenn die Quelle
//wurde nicht mit der Player-API aktualisiert
wenn (! this.changeSRC_) {
lass UpdateSourceCaches = (src) => this.UpdateSourceCaches_ (src);
const playerSrc = this.currentSource () .src;
const eventSrc = event.src;
//wenn wir einen PlayerSrc haben, der kein Blob ist, und einen Tech-Src, der ein Blob ist
wenn (PlayersRC &&! (/^blob:/) .test (playersRC) && (/^blob:/) .test (EventSrc)) {
//wenn sowohl die Tech-Quelle als auch die Player-Quelle aktualisiert wurden, gehen wir davon aus
//etwas wie @videojs /http-streaming hat den Sourceset gemacht und die Aktualisierung des Quellcaches übersprungen.
wenn (! This.LastSource_ || (This.LastSource_.tech! == EventSrc & this.LastSource_.Player! == SpielerRC)) {
updateSourceCaches = () => {};
}
}
//aktualisiere die Quelle sofort auf die ursprüngliche Quelle
//in einigen Fällen ist dies eine leere Zeichenfolge
Quellcaches aktualisieren (EventSrc);
//wenn das `sourceset` `src` ein leerer String wäre
//warte auf einen `loadstart` um den Cache auf `currentSrc` zu aktualisieren.
//Wenn ein Sourceset vor einem `Loadstart` passiert, setzen wir den Zustand zurück
wenn (! event.src) {
this.tech_.any (['Quellset', 'loadstart'], (e) => {
//wenn dort ein Sourceset vor einem `Loadstart` passiert
//ist nichts zu tun wie das `handleTechSourceSet_`
//wird erneut aufgerufen und das wird dort erledigt.
if (e.type === 'Quellsatz') {
rückkehr;
}
const techSRC = this.techGet ('CurrentSrc');
this.lastsource_.tech = TechSRC;
this.updateSourceCaches_ (TechSRC);
});
}
}
this.lastSource_ = {Spieler: this.currentSource () .src, tech: event.src};
this.trigger({
src: event.src,
typ: 'Quellensatz'
});
}
/**
* Fügt die Klasse vjs-has-started hinzu oder entfernt sie
*
* @Feuer Spieler#Erstes Spiel
*
* @param {boolean} Anfrage
* - true: fügt die Klasse hinzu
* - false: Entferne die Klasse
*
* @return {boolean}
* der boolesche Wert von hasStarted_
* /
hasStarted (Anfrage) {
if (Anfrage === undefiniert) {
//agiere als Getter, wenn wir keine Änderungswünsche haben
gib this.hasStarted_ zurück;
}
if (anfrage === this.hasStarted_) {
rückkehr;
}
this.hasStarted_ = Anfrage;
if (this.hasStarted_) {
this.addClass('vjs-has-started');
this.trigger('firstplay');
} sonst {
this.removeClass ('vjs wurde gestartet');
}
}
/**
* Wird ausgelöst, wenn das Medium die Wiedergabe beginnt oder fortsetzt
*
* @see [Spezifikation] {@link https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-play}
* @fires Spieler #play
* @listens Tech#play
* @privat
* /
handleTechPlay_ () {
this.removeClass('vjs-ended');
this.removeClass('vjs-paused');
this.addClass('vjs-playing');
//verstecke das Poster, wenn der Benutzer auf Play klickt
this.hasStarted (wahr);
/**
* Wird immer dann ausgelöst, wenn ein {@link Tech #play} -Ereignis eintritt. Zeigt an, dass
* Die Wiedergabe wurde gestartet oder fortgesetzt.
*
* @event Spieler #play
* @Typ {EventTarget~Event}
* /
this.trigger ('abspielen');
}
/**
* Das `ratechange`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* Wenn sich Ereignisse in der Warteschlange befanden, während die Wiedergabegeschwindigkeit Null war, starten Sie
* diese Ereignisse jetzt.
*
* @privat
* @method Spieler #handleTechRateChange_
* @fires Spieler #ratechange
* @listens Technik #ratechange
* /
handleTechrateChange_ () {
if (this.tech_.playbackRate () > 0 && this.Cache_.lastPlaybackRate === 0) {
this.queuedCallbacks_.forEach ((in die Warteschlange gestellt) => in die Warteschlange gestellt.callback (in die Warteschlange gewartet.event));
this.queuedCallbacks_ = [];
}
this.cache_.lastPlaybackRate = this.tech_.playbackRate ();
/**
* Wird ausgelöst, wenn die Wiedergabegeschwindigkeit des Audios/Videos geändert wird
*
* @event Spieler #ratechange
* @Typ {Ereignis}
* /
this.trigger ('Ratenänderung');
}
/**
* Das `waiting`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @fires Spieler #waiting
* @listens Technik #waiting
* @privat
* /
handleTechWaiting_ () {
this.addClass ('vjs-waiting');
/**
* Eine ReadyState-Änderung am DOM-Element hat dazu geführt, dass die Wiedergabe gestoppt wurde.
*
* @event Spieler #waiting
* @Typ {EventTarget~Event}
* /
this.trigger ('wartet');
//Browser können nach einem Warteereignis ein Timeupdate-Ereignis ausgeben. Um zu verhindern
//vorzeitiges Entfernen der Warteklasse, warte auf die Änderung der Uhrzeit.
const timeWhenWaiting = this.currentTime ();
const timeUpdateListener = () => {
if (timeWhenWaiting! == this.currentTime ()) {
this.removeClass('vjs-waiting');
this.off ('timeupdate', timeUpdateListener);
}
};
this.on ('timeupdate', timeUpdateListener);
}
/**
* Das `canplay`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
* > Anmerkung: Dies ist zwischen Browsern nicht konsistent. Siehe #1351
*
* @fires Spieler #canplay
* @listens Technik #canplay
* @privat
* /
handleTechCanPlay_ () {
this.removeClass('vjs-waiting');
/**
* Das Medium hat einen ReadyState von HAVE_FUTURE_DATA oder höher.
*
* @event Spieler #canplay
* @Typ {EventTarget~Event}
* /
this.trigger ('kann abspielen');
}
/**
* Das `canplaythrough`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @fires Spieler #canplaythrough
* @listens Technik #canplaythrough
* @privat
* /
handleTechCanPlaythrough_ () {
this.removeClass('vjs-waiting');
/**
* Das Medium hat einen ReadyState von HAVE_ENOUGH_DATA oder höher. Das bedeutet, dass
* Die gesamte Mediendatei kann ohne Pufferung abgespielt werden.
*
* @event Spieler #canplaythrough
* @Typ {EventTarget~Event}
* /
this.trigger ('kann durchspielen');
}
/**
* Löse das `playing`-Event erneut aus, das vom {@link Tech} ausgelöst wurde.
*
* @fires Spieler #playing
* @listens Technik #playing
* @privat
* /
HandleTechPlaying_ () {
this.removeClass('vjs-waiting');
/**
* Das Medium ist nicht mehr für die Wiedergabe gesperrt und die Wiedergabe hat begonnen.
*
* @event Spieler #playing
* @Typ {EventTarget~Event}
* /
this.trigger ('wird abgespielt');
}
/**
* Das `seeking`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @fires Spieler #seeking
* @listens Technik #seeking
* @privat
* /
handleTechSeeking_ () {
this.addClass ('vjs-seeking');
/**
* Wird immer dann abgefeuert, wenn der Spieler zu einer neuen Zeit springt
*
* @event Spieler #seeking
* @Typ {EventTarget~Event}
* /
this.trigger ('sucht');
}
/**
* Das `seeked`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @fires Spieler #seeked
* @listens Technik #seeked
* @privat
* /
handleTechSeeked_ () {
this.removeClass('vjs-seeking');
this.removeClass('vjs-ended');
/**
* Wird abgefeuert, wenn der Spieler mit dem Sprung in eine neue Zeit fertig ist
*
* @event Spieler #seeked
* @Typ {EventTarget~Event}
* /
this.trigger ('gesucht');
}
/**
* Das `firstplay`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @Feuer Spieler#Erstes Spiel
* @listens Technik #firstplay
* @deprecated Ab 6.0 ist das Ereignis firstplay veraltet.
* Ab 6.0 sind das Übergeben der Option `starttime` an den Spieler und das Firstplay-Event veraltet.
* @privat
* /
handleTechFirstPlay_ () {
//Wenn das erste Starttime-Attribut angegeben ist
//dann beginnen wir mit dem angegebenen Offset in Sekunden
wenn (this.options_.starttime) {
log.warn ('Die Option `starttime` an den Spieler weiterzugeben wird in 6.0 veraltet sein');
this.currentTime (this.options_.starttime);
}
this.addClass('vjs-has-started');
/**
* Wird ausgelöst, wenn ein Video zum ersten Mal abgespielt wird. Nicht Teil der HLS-Spezifikation, und das ist
* wahrscheinlich noch nicht die beste Implementierung, also sparsam verwenden. Wenn Sie keine haben
* Um die Wiedergabe zu verhindern, verwenden Sie stattdessen `myPlayer.one ('play'); `.
*
* @event Spieler #firstplay
* @deprecated Ab 6.0 ist das Ereignis firstplay veraltet.
* @Typ {EventTarget~Event}
* /
this.trigger('firstplay');
}
/**
* Das `Pause`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @fires Spieler #pause
* @listens Technik #pause
* @privat
* /
handleTechPause_ () {
this.removeClass('vjs-playing');
this.addClass('vjs-paused');
/**
* Wird immer dann ausgelöst, wenn die Medien angehalten wurden
*
* @event Spieler #pause
* @Typ {EventTarget~Event}
* /
this.trigger ('Pause');
}
/**
* Das `endet` Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @fires Spieler #ended
* @listens Technik #ended
* @privat
* /
handleTechended_ () {
this.addClass('vjs-ended');
this.removeClass('vjs-waiting');
wenn (this.options_.loop) {
this.currentTime(0);
dieses.play ();
} sonst wenn (! this.pausiert ()) {
this.pause();
}
/**
* Wird ausgelöst, wenn das Ende der Medienressource erreicht ist (CurrentTime == Dauer)
*
* @event Spieler #ended
* @Typ {EventTarget~Event}
* /
this.trigger ('beendet');
}
/**
* Wird ausgelöst, wenn die Dauer der Medienressource zum ersten Mal bekannt ist oder geändert wird
*
* @listens Tech#durationchange
* @privat
* /
handleTechDurationChange_ () {
this.duration (this.techGet_ ('Dauer'));
}
/**
* Klicken Sie mit einem Klick auf das Medienelement, um es abzuspielen oder zu pausieren
*
* @param {EventTarget~Event} event
* das Ereignis, das diese Funktion ausgelöst hat
*
* @listens Technik #click
* @privat
* /
handleTechClick_ (Ereignis) {
//Wenn die Steuerung deaktiviert ist, sollte ein Klick die Wiedergabe nicht umschalten, weil
//der Klick wird als Kontrolle betrachtet
if (!this.controls_) {
rückkehr;
}
wenn (
this.options_ === undefiniert ||
this.options_.userActions === undefiniert ||
this.options_.UserActions.click === undefiniert ||
This.Options_.UserActions.Click! == falsch
) {
wenn (
this.options_ !== undefiniert &&
this.options_.userActions !== undefiniert &&
typeofthis.options_.userActions.click === 'Funktion'
) {
this.options_.userActions.click.call (dies, Ereignis);
} sonst wenn (this.paused ()) {
SilencePromise (this.play ());
} sonst {
this.pause();
}
}
}
/**
* Doppelklicken Sie auf das Medienelement, um den Vollbildmodus aufzurufen oder zu verlassen
*
* @param {EventTarget~Event} event
* das Ereignis, das diese Funktion ausgelöst hat
*
* @listens Technik #dblclick
* @privat
* /
handleTechDoubleClick_ (Ereignis) {
if (!this.controls_) {
rückkehr;
}
//wir wollen den Vollbildmodus nicht umschalten
//beim Doppelklicken in eine Kontrollleiste oder ein Modal
const inAllowEdels = Array.prototype.some.call (
dieses.$$ ('.vjs-control-bar, .vjs-modal-dialog'),
de => el.contains (event.target)
);
wenn (! in Allowels) {
/*
* Optionen. Benutzeraktionen. Doppelklicken
*
* Bei `undefined` oder `true` schaltet ein Doppelklick den Vollbildmodus um, sofern Steuerelemente vorhanden sind
* Auf `false` setzen, um die Doppelklickverarbeitung zu deaktivieren
* Auf eine Funktion setzen, die einen externen Doppelklick-Handler ersetzt
* /
wenn (
this.options_ === undefiniert ||
this.options_.userActions === undefiniert ||
this.options_.UserActions.DoubleClick === undefiniert ||
this.options_.userActions.Doubleclick! == falsch
) {
wenn (
this.options_ !== undefiniert &&
this.options_.userActions !== undefiniert &&
typeof this.options_.userActions.DoubleClick === 'Funktion'
) {
this.options_.userActions.DoubleClick.Call (dies, Ereignis);
} sonst wenn (this.isFullScreen ()) {
this.exitFullscreen();
} sonst {
this.requestFullScreen ();
}
}
}
}
/**
* Tippen Sie einfach auf das Medienelement. Es wird den Benutzer umschalten
* Aktivitätsstatus, in dem die Steuerelemente ein- und ausgeblendet werden.
*
* @listens Technik #tap
* @privat
* /
handleTechTap_ () {
this.userActive (! this.userActive ());
}
/**
* Berühren Sie zum Starten
*
* @listens Technik #touchstart
* @privat
* /
handleTechTouchStart_ () {
this.userWasActive = this.userActive ();
}
/**
* Berühren Sie, um sich zu bewegen
*
* @listens Technik #touchmove
* @privat
* /
handleTechTouchMove_ () {
wenn (this.userWasActive) {
this.reportUserActivity();
}
}
/**
* Berühren Sie bis zum Ende
*
* @param {EventTarget~Event} event
* das berührende Ereignis, das ausgelöst hat
* diese Funktion
*
* @listens Technik #touchend
* @privat
* /
handleTechTouchEnd_ (Veranstaltung) {
//Stoppt, dass auch Mausereignisse passieren
wenn (event.cancelable) {
event.preventDefault();
}
}
/**
* native Klickereignisse auf der SWF werden unter IE11, Win8.1RT nicht ausgelöst
* verwende stattdessen Stageclick-Ereignisse, die innerhalb der SWF ausgelöst wurden
*
* @privat
* @listens Stageclick
* /
handleStageClick_ () {
this.reportUserActivity();
}
/**
* @privat
* /
toggleFullScreenClass_ () {
if (this.isFullscreen()) {
this.addClass ('vjs-fullscreen');
} sonst {
this.removeClass ('vjs-fullscreen');
}
}
/**
* wenn das Fschange-Ereignis des Dokuments ausgelöst wird, ruft es dies auf
* /
documentFullScreenChange_ (e) {
const targetPlayer = e.target.player;
//wenn ein anderer Spieler im Vollbildmodus war
//führe einen Nullcheck für TargetPlayer durch, da ältere Firefox's das Dokument als e.target angeben würden
wenn (TargetPlayer && TargetPlayer! == das) {
rückkehr;
}
const el = this.el ();
sei isFS = document [this.FSAPI_.FullScreenElement] === el;
wenn (! ISFs & el.matches) {
isFS = el.matches (':' + this.fsapi_.FullScreen);
} sonst wenn (! isFS && el.msMatchesSelector) {
isFS = el.msMatchesSelector (':' + this.fsapi_.FullScreen);
}
this.isFullScreen (iSFS);
}
/**
* Technische Änderung im Vollbildmodus durchführen
*
* @param {EventTarget~Event} event
* das FullscreenChange-Ereignis, das diese Funktion ausgelöst hat
*
* @param {Object} data
* die Daten, die mit der Veranstaltung gesendet wurden
*
* @privat
* @listens Technik #fullscreenchange
* @fires Player#fullscreenchange
* /
handleTechFullScreenChange_ (Ereignis, Daten) {
wenn (Daten) {
wenn (data.nativeIOSFullScreen) {
this.addClass ('vjs-ios-native-fs');
this.tech_.one ('webkitendfullscreen', () => {
this.removeClass ('vjs-ios-native-fs');
});
}
this.isFullScreen (Data.isFullScreen);
}
}
handleTechFullScreenError_ (Ereignis, Fehler) {
this.trigger ('Vollbildfehler', Fehler);
}
/**
* @privat
* /
TogglePictureClass_ () {
if (this.isInPictureInPicture()) {
this.addClass ('vjs-bild-im-bild-im-bild-');
} sonst {
this.removeClass ('vjs-bild-im-bild');
}
}
/**
* Handle Tech Geben Sie Bild im Bild ein.
*
* @param {EventTarget~Event} event
* das enterpictureinpicture-Ereignis, das diese Funktion ausgelöst hat
*
* @privat
* @listens Technik #enterpictureinpicture
* /
handleTechenterPictureInPicture_ (Ereignis) {
this.isinPictureInPicture (wahr);
}
/**
* Handle Tech Leave Bild-im-Bild.
*
* @param {EventTarget~Event} event
* das leavePictureInPictureInPicture-Ereignis, das diese Funktion ausgelöst hat
*
* @privat
* @listens Technik #leavepictureinpicture
* /
handleTechLeavePictureInPicture_ (Ereignis) {
this.isInPictureInPicture (falsch);
}
/**
* Wird ausgelöst, wenn beim Laden eines Audio/Videos ein Fehler aufgetreten ist.
*
* @privat
* @listens Technik #error
* /
HandletechError_ () {
konstanter Fehler = this.tech_.error ();
this.error (Fehler);
}
/**
* Das `Textdata`-Ereignis, das vom {@link Tech} ausgelöst wurde, erneut auslösen.
*
* @fires Spieler #textdata
* @listens Technik #textdata
* @privat
* /
handleTechTextData_ () {
sei data = null;
wenn (arguments.length > 1) {
Daten = Argumente [1];
}
/**
* Wird ausgelöst, wenn wir ein Textdaten-Ereignis vom Techniker erhalten
*
* @event Spieler #textdata
* @Typ {EventTarget~Event}
* /
this.trigger ('Textdaten', Daten);
}
/**
* Ruft ein Objekt für zwischengespeicherte Werte ab.
*
* @return {Object}
* holt den aktuellen Objekt-Cache
* /
getCache () {
gib this.cache_ zurück;
}
/**
* Setzt das interne Cache-Objekt zurück.
*
* Wenn Sie diese Funktion außerhalb des Player-Konstruktors oder der Reset-Methode verwenden, können
* haben unbeabsichtigte Nebenwirkungen.
*
* @privat
* /
resetCache_ () {
dieser.cache_ = {
//Im Moment wird die CurrentTime nicht _wirklich_ zwischengespeichert, weil sie immer
//vom Techniker abgerufen (siehe: CurrentTime). Der Vollständigkeit halber
//wir setzen es hier auf Null, um sicherzustellen, dass wir, falls wir das tun, tatsächlich mit dem Caching beginnen
//es, wir setzen es zusammen mit allem anderen zurück.
aktuelleZeit: 0,
InitTime: 0,
InactivityTimeout: this.options_.inactivityTimeout,
Dauer: NaN,
Letzter Band: 1,
lastPlaybackRate: this.defaultPlaybackRate (),
Medien: null,
src: „,
Quelle: {},
quellen: [],
playbackRates: [],
volumen: 1
};
}
/**
* Werte an die Wiedergabe-Technologie übergeben
*
* @param {string} [Methode]
* die Methode zum Aufrufen
*
* @param {Objekt} arg
* das zu übergebende Argument
*
* @privat
* /
techCall_ (Methode, arg) {
//Wenn es noch nicht fertig ist, rufe Methode auf, wenn es soweit ist
this.ready(function() {
if (Methode in Middleware.allowedSetters) {
gib middleware.set (this.middleware_, this.tech_, method, arg) zurück;
} else if (Methode in middleware.allowedMediators) {
gib middleware.mediate (this.middleware_, this.tech_, method, arg) zurück;
}
versuche {
if (this.tech_) {
this.tech_ [Methode] (arg);
}
} catch (e) {
log(e);
werfen e;
}
}, true);
}
/**
* Get Calls kann nicht auf die Technik warten und muss es manchmal auch nicht.
*
* @param {string} -Methode
* Technische Methode
*
* @return {Funktion|undefined}
* die Methode oder undefiniert
*
* @privat
* /
TechGet_ (Methode) {
wenn (! this.tech_ ||! this.tech_.isReady_) {
rückkehr;
}
if (Methode in Middleware.allowedGetters) {
gib middleware.get (this.middleware_, this.tech_, method) zurück;
} else if (Methode in middleware.allowedMediators) {
gib middleware.mediate (this.middleware_, this.tech_, method) zurück;
}
//Flash stirbt gerne und lädt neu, wenn du es versteckst oder neu positionierst.
//In diesen Fällen verschwinden die Objektmethoden und wir erhalten Fehler.
// TODO: Wird das für andere Techniker als Flash benötigt?
//Wenn das passiert, werden wir die Fehler erkennen und die Techniker darüber informieren, dass es nicht mehr bereit ist.
versuche {
gib this.tech_ [Methode] () zurück;
} catch (e) {
//Beim Erstellen zusätzlicher Tech Libs ist eine erwartete Methode möglicherweise noch nicht definiert
if (this.tech_ [Methode] === undefiniert) {
log (`Video.js: Die $ {method} -Methode ist für die $ {this.techName_} -Wiedergabe-Technologie nicht definiert.`, e);
werfen e;
}
//Wenn eine Methode für das Objekt nicht verfügbar ist, wird ein TypeError ausgelöst
if (e.name === 'TypeError') {
log (`Video.js: $ {method} ist für das $ {this.techName_} -Element der Wiedergabe-Technologie nicht verfügbar.`, e);
this.tech_.isReady_ = falsch;
werfen e;
}
//Wenn der Fehler unbekannt ist, einfach loggen und werfen
log(e);
werfen e;
}
}
/**
* Versuchen Sie, die Wiedergabe bei der ersten Gelegenheit zu starten.
*
* @return {Versprechen|undefiniert}
* Gibt ein Versprechen zurück, wenn der Browser Promises unterstützt (oder eines
* wurde als Option übergeben). Dieses Versprechen wird am eingelöst
* der Rückgabewert von Play. Wenn dies undefiniert ist, erfüllt es die
* Versprechenskette andernfalls wird die Versprechenskette erfüllt, wenn
* Das Spielversprechen ist erfüllt.
* /
abspielen () {
const PromiseClass = this.options_.Promise || window.Promise;
if (PromiseClass) {
gib eine neue PromiseClass zurück ((resolve) => {
this.play_ (lösen);
});
}
gib this.play_ () zurück;
}
/**
* Die eigentliche Logik für das Abspielen erfordert einen Rückruf, der auf der
* gibt den Wert des Spiels zurück. Dies ermöglicht es uns, das Spielversprechen einzuhalten, falls
* ist eines in modernen Browsern.
*
* @privat
* @param {Funktion} [Rückruf]
* Der Callback, der aufgerufen werden soll, wenn die Techniker spielen, wird tatsächlich aufgerufen
* /
play_ (Rückruf = SilencePromise) {
this.playCallbacks_.push (Rückruf);
const issrcReady = Boolean (! this.changeSRC_ && (this.src () || this.currentSrc ()));
//behandle Aufrufe von play_ irgendwie wie die `one` Event-Funktion
wenn (this.waitToPlay_) {
this.off (['bereit', 'loadstart'], this.waitToPlay_);
this.waitToPlay_ = null;
}
//wenn der Player/Tech noch nicht bereit ist oder der SRC selbst noch nicht bereit ist
//einen Anruf in die Warteschlange stellen, um auf `ready` oder `loadstart` abzuspielen
wenn (! Das.ist bereit _ ||! ist SRC bereit) {
this.waitToPlay_ = (e) => {
this.play_ ();
};
this.one (['bereit', 'loadstart'], this.waitToPlay_);
//Wenn wir in Safari sind, besteht eine hohe Wahrscheinlichkeit, dass der Ladestart nach dem Zeitraum der Geste ausgelöst wird
//in diesem Fall müssen wir das Videoelement vorbereiten, indem wir load aufrufen, damit es rechtzeitig fertig ist
wenn (! issrcReady & (browser.is_ANY_Safari | Browser.is_iOS)) {
this.load ();
}
rückkehr;
}
//Wenn der Player/Techniker bereit ist und wir eine Quelle haben, können wir die Wiedergabe versuchen.
const val = this.techGet_ ('abspielen');
//Das Spiel wurde beendet, wenn der zurückgegebene Wert Null ist
wenn (val === null) {
this.runPlayTerminatedQueue_ ();
} sonst {
this.runPlayCallbacks_ (val);
}
}
/**
* Diese Funktionen werden ausgeführt, wenn das Spiel beendet ist. Wenn spiele
* RunPlayCallbacks_ ist ausgeführt, diese Funktion wird nicht ausgeführt. Das ermöglicht uns
* um zwischen einem abgebrochenen Spiel und einem tatsächlichen Call to Play zu unterscheiden.
* /
runPlayTerminatedQueue_ () {
const queue = this.playTerminatedQueue_.slice (0);
this.playTerminatedQueue_ = [];
queue.forEach (Funktion (q) {
q ();
});
}
/**
* Wenn sich ein Rückruf zum Abspielen verzögert, müssen wir diese ausführen
* Rückrufe, wenn das Spiel tatsächlich vom Techniker aufgerufen wird. Diese Funktion
* führt die verzögerten Callbacks aus und akzeptiert den Rückgabewert
* von der Technik.
*
* @param {undefined|Promise} val
* Der Rückgabewert des Technikers.
* /
runPlayCallbacks_ (val) {
const Callbacks = this.playCallbacks_.slice (0);
this.playCallbacks_ = [];
//Clear Play TerminatedQueue, da wir ein echtes Spiel beendet haben
this.playTerminatedQueue_ = [];
callbacks.forEach (function (cb) {
cb (oval);
});
}
/**
* Unterbrechen Sie die Videowiedergabe
*
* @return {Player}
* Ein Verweis auf das Spielerobjekt, für das diese Funktion aufgerufen wurde
* /
Pause () {
this.techCall_ ('Pause');
}
/**
* Überprüfe, ob der Spieler angehalten hat oder noch nicht gespielt hat
*
* @return {boolean}
* - falsch: wenn das Medium gerade abgespielt wird
* - wahr: wenn das Medium gerade nicht abgespielt wird
* /
angehalten () {
//Der Anfangszustand von pausiert sollte wahr sein (in Safari ist er tatsächlich falsch)
return (this.techGet_ ('pausiert') === falsch)? falsch: wahr;
}
/**
* Ruft ein TimeRange-Objekt ab, das die aktuellen Zeitbereiche darstellt, die der Benutzer
* hat gespielt.
*
* @return {TimeRange}
* Ein Zeitbereichsobjekt, das alle Zeitintervalle darstellt, die
* wurde gespielt.
* /
gespielt() {
gib this.techGet_ ('gespielt') || createTimeRange (0, 0) zurück;
}
/**
* Gibt zurück, ob der Benutzer „scrubbt“ oder nicht. Schrubben ist
* wenn der Benutzer auf den Fortschrittsbalken geklickt hat und
* Ziehen Sie es entlang des Fortschrittsbalkens.
*
* @param {boolean} [isScrubbing]
* ob der Benutzer schrubbt oder nicht
*
* @return {boolean}
* Der Wert des Schrubbens beim Schrubben
* /
schrubben (isScrubbing) {
if (typeof isScrubbing === 'undefiniert') {
gib this.scrubbing_ zurück;
}
this.scrubbing_ =!! schrubbt;
this.techCall_ ('setScrubbing', this.scrubbing_);
wenn (isScrubbing) {
this.addClass ('vjs-Scrubbing');
} sonst {
this.removeClass ('vjs-scrubbing');
}
}
/**
* Aktuelle Uhrzeit abrufen oder einstellen (in Sekunden)
*
* @param {number|string} [Sekunden]
* Die Zeit, nach der gesucht werden muss, in Sekunden
*
* @return {number}
* - die aktuelle Uhrzeit in Sekunden beim Abrufen
* /
CurrentTime (Sekunden) {
if (Art der Sekunden! == 'undefiniert') {
if (Sekunden < 0) {
Sekunden = 0;
}
wenn (! Das.IsReady_ || Das.ChangingSRC_ ||! this.tech_ ||! this.tech_.isReady_) {
this.cache_.initTime = Sekunden;
this.off ('kann abspielen', this.boundApplyInitTime_);
this.one ('kann abspielen', this.boundApplyInitTime_);
rückkehr;
}
this.techCall_ ('setCurrentTime', Sekunden);
this.cache_.initTime = 0;
rückkehr;
}
//letzte CurrentTime zwischenspeichern und zurückgeben. Der Standardwert ist 0 Sekunden
// //
//Das Caching der CurrentTime soll eine massive Menge an Lesevorgängen auf den Technikern verhindern
//CurrentTime beim Scrubben, bietet aber möglicherweise doch keinen großen Leistungsvorteil.
//Sollte getestet werden. Außerdem muss etwas die aktuelle Uhrzeit ablesen, sonst wird der Cache
//werde nie aktualisiert.
this.cache_.currentTime = (this.techGet_ ('CurrentTime') || 0);
gib this.cache_.currentTime zurück;
}
/**
* Wenden Sie den im Cache gespeicherten Wert von initTime als CurrentTime an.
*
* @privat
* /
applyInitTime_ () {
this.currentTime (this.cache_.initTime);
}
/**
* Ruft normalerweise die Länge des Videos in Sekunden ab;
* in allen außer den seltensten Anwendungsfällen wird ein Argument NICHT an die Methode übergeben
*
* > **HINWEIS**: Das Video muss mit dem Laden begonnen haben, bevor die Dauer erreicht werden kann
* bekannt, und je nach Preload-Verhalten möglicherweise erst bekannt, wenn das Video gestartet wird
* spielen.
*
* @fires Spieler #durationchange
*
* @param {Zahl} [Sekunden]
* Die Dauer des Videos, die eingestellt werden sollen, in Sekunden
*
* @return {number}
* - Die Dauer des Videos in Sekunden beim Abrufen
* /
Dauer (Sekunden) {
if (Sekunden === undefiniert) {
//gib NaN zurück, wenn die Dauer nicht bekannt ist
gib this.cache_.duration zurück! == undefiniert? this.cache_.duration: NaN;
}
Sekunden = parseFloat (Sekunden);
//Standardisieren Sie auf Infinity, um zu signalisieren, dass das Video live ist
if (Sekunden < 0) {
Sekunden = Unendlich;
}
wenn (Sekunden! == this.cache_.duration) {
//Den zuletzt eingestellten Wert für optimiertes Scrubbing zwischenspeichern (insb. Blitz)
// TODO: Benötigen Sie andere Technologien als Flash?
this.cache_.duration = Sekunden;
if (Sekunden === Unendlich) {
this.addClass ('vjs-live');
} sonst {
this.removeClass ('vjs-live');
}
wenn (! Sinan (Sekunden) {
//DurationChange nicht auslösen, es sei denn, der Wert für die Dauer ist bekannt.
// @see [Spec]{@link https://www.w3.org/TR/2011/WD-html5-20110113/video.html#media-element-load-algorithm}
/**
* @event Spieler #durationchange
* @Typ {EventTarget~Event}
* /
this.trigger('Daueränderung');
}
}
}
/**
* Berechnet, wie viel Zeit im Video noch übrig ist. Kein Teil
* der nativen Video-API.
*
* @return {number}
* Die verbleibende Zeit in Sekunden
* /
Verbleibende Zeit () {
gib this.duration () - this.currentTime () zurück;
}
/**
* Eine Restzeitfunktion, die verwendet werden soll, wenn
* Die Uhrzeit soll dem Benutzer direkt angezeigt werden.
*
* @return {number}
* Die gerundete verbleibende Zeit in Sekunden
* /
Anzeige der verbleibenden Zeit () {
gib Math.floor (this.duration ()) zurück - Math.floor (this.currentTime ());
}
// //
//So etwas wie eine Reihe von Teilen des Videos, die heruntergeladen wurden.
/**
* Holen Sie sich ein TimeRange-Objekt mit einem Array der Zeiten des Videos
* die heruntergeladen wurden. Wenn Sie nur den Prozentsatz der
* Video, das heruntergeladen wurde, verwende BufferedPercent.
*
* @see [Gepufferte Spezifikation] {@link http://dev.w3.org/html5/spec/video.html#dom-media-buffered}
*
* @return {TimeRange}
* Ein simuliertes TimeRange-Objekt (folgt der HTML-Spezifikation)
* /
gepuffert() {
let buffered = this.techGet_ ('gepuffert');
if (!buffered || !buffered.length) {
gepuffert = createTimeRange(0, 0);
}
Rückkehr gepuffert;
}
/**
* Ermittelt den Prozentsatz (als Dezimalzahl) des heruntergeladenen Videos.
* Diese Methode ist nicht Teil der nativen HTML-Video-API.
*
* @return {number}
* Eine Dezimalzahl zwischen 0 und 1, die den Prozentsatz darstellt
* das ist gepuffert, 0 steht für 0% und 1 für 100
* /
bufferedPercent() {
gib bufferedPercent (this.buffered (), this.duration ()) zurück;
}
/**
* Ruft die Endzeit des letzten gepufferten Zeitbereichs ab
* Dies wird in der Fortschrittsleiste verwendet, um alle Zeitbereiche zu kapseln.
*
* @return {number}
* Das Ende des letzten gepufferten Zeitbereichs
* /
bufferEndend () {
const buffered = this.buffered ();
konstante Dauer = this.duration ();
sei end = buffered.end (buffered.length - 1);
wenn (Ende > Dauer) {
ende = Dauer;
}
Ende der Rückfahrt;
}
/**
* Rufen Sie die aktuelle Lautstärke des Mediums ab oder stellen Sie sie ein
*
* @param {Zahl} [percentAsDecimal]
* Das neue Volumen als Dezimalprozent:
* - 0 ist stumm/0%/aus
* - 1.0 ist 100 %/vollständig
* - 0,5 ist das halbe Volumen oder 50%
*
* @return {number}
* Die aktuelle Lautstärke in Prozent beim Abrufen
* /
Volumen (PercentAsDecimal) {
lass es fliegen;
wenn (PercentAsDecimal! == undefiniert) {
//Wert auf einen Wert zwischen 0 und 1 zwingen
vol = Math.max (0, Math.min (1, parseFloat (PercentAsDecimal)));
this.cache_.volume = Band;
this.techCall_ ('setVolume', vol);
wenn (Band > 0) {
this.lastVolume_ (vol);
}
rückkehr;
}
//Der Standardwert ist 1, wenn die aktuelle Lautstärke zurückgegeben wird.
vol = parseFloat (this.techGet_ ('Volumen'));
return (isNaN (vol))? 1: Band;
}
/**
* Ermitteln Sie den aktuellen Stummschaltzustand oder schalten Sie die Stummschaltung ein oder aus
*
* @param {boolean} [stummgeschaltet]
* - true zum Stummschalten
* - false zum Aufheben der Stummschaltung
*
* @return {boolean}
* - wahr, wenn die Stummschaltung an ist und wird
* - falsch, wenn die Stummschaltung aus ist und
* /
stummgeschaltet (stummgeschaltet) {
wenn (stummgeschaltet! == undefiniert) {
this.techCall_ ('setMuted', stummgeschaltet);
rückkehr;
}
gib this.techGet_ ('stummgeschaltet') || false zurück;
}
/**
* Ruft den aktuellen DefaultMuted-Status ab oder schaltet DefaultMuted ein oder aus. defaultMuted
* zeigt den Stummschaltzustand bei der ersten Wiedergabe an.
*
* ``js
* var myPlayer = videojs ('some-player-id');
*
* MyPlayer.src (“ http://www.example.com/path/to/video.mp4 „);
*
*//get, sollte falsch sein
* console.log(myPlayer.defaultMuted());
*//auf true gesetzt
* myPlayer.defaultMuted (wahr);
*//get sollte wahr sein
* console.log(myPlayer.defaultMuted());
* ```
*
* @param {boolean} [DefaultStummgeschaltet]
* - true zum Stummschalten
* - false zum Aufheben der Stummschaltung
*
* @return {boolean|Spieler}
* - wahr, wenn defaultMuted aktiviert ist und
* - false wenn defaultMuted ausgeschaltet ist und
* - Ein Verweis auf den aktuellen Spieler beim Einstellen
* /
Standardstummgeschaltet (DefaultStummgeschaltet) {
if (defaultStummgeschaltet! == undefiniert) {
gib this.techCall_ ('setDefaultMuted', defaultMuted) zurück;
}
gib this.techGet_ ('defaultMuted') zurück || false;
}
/**
* Holen Sie sich die letzte Lautstärke oder stellen Sie sie ein
*
* @param {Zahl} [percentAsDecimal]
* Das neue letzte Volumen als Dezimalprozent:
* - 0 ist stumm/0%/aus
* - 1.0 ist 100 %/vollständig
* - 0,5 ist das halbe Volumen oder 50%
*
* @return {number}
* der aktuelle Wert von LastVolume als Prozentsatz beim Abrufen
*
* @privat
* /
LastVolume_ (Prozentsätze als Dezimalzahl) {
wenn (PercentAsDecimal! = undefiniert & PercentasDecimal! == 0) {
this.cache_.lastVolume = Prozentwert als Dezimalzahl;
rückkehr;
}
gib this.cache_.lastVolume zurück;
}
/**
* Prüfen Sie, ob die aktuelle Technologie den nativen Vollbildmodus unterstützt
* (z. B. mit integrierten Steuerelementen wie iOS)
*
* @return {boolean}
* wenn nativer Vollbildschirm unterstützt wird
* /
supportsFullScreen() {
gib this.techGet_ ('supportsFullScreen') zurück || false;
}
/**
* Überprüfe, ob sich der Player im Vollbildmodus befindet, oder teile dem Spieler mit, dass er
* ist oder ist nicht im Vollbildmodus.
*
* > HINWEIS: Ab der neuesten HTML5-Spezifikation ist isFullScreen kein offizieller
* Eigenschaft und stattdessen Document.FullScreenElement wird verwendet. Aber isFullScreen ist
* immer noch ein wertvolles Eigentum für interne Spielerabläufe.
*
* @param {boolean} [ISFs]
* Stellen Sie den aktuellen Vollbildstatus des Spielers ein
*
* @return {boolean}
* - wahr, wenn der Vollbildmodus aktiviert ist und
* - falsch wenn der Vollbildmodus ausgeschaltet ist und
* /
isFullScreen (iSFS) {
wenn (ISFs! == undefiniert) {
const oldValue = this.isFullScreen_;
this.isFullScreen_ = Boolescher Wert (iSFS);
//Wenn wir den Vollbildstatus geändert haben und wir uns im Präfixmodus befinden, lösen Sie den Vollbildwechsel aus
//dies ist der einzige Ort, an dem wir FullscreenChange-Ereignisse für ältere Browser auslösen
//Der FullWindow-Modus wird als Ereignis mit Präfix behandelt und erhält auch ein FullscreenChange-Ereignis
wenn (this.isFullScreen_! == Alter Wert & this.fapi_.Präfix) {
/**
* @event Spieler #fullscreenchange
* @Typ {EventTarget~Event}
* /
this.trigger ('Vollbildwechsel');
}
this.toggleFullScreenClass_ ();
rückkehr;
}
gib this.isFullScreen_ zurück;
}
/**
* Erhöhen Sie die Größe des Videos auf den Vollbildmodus
* In einigen Browsern wird der Vollbildmodus nativ nicht unterstützt, daher wird
* „Vollfenstermodus“, in dem das Video das Browserfenster füllt.
* In Browsern und Geräten, die den nativen Vollbildmodus unterstützen, manchmal
* Die Standardsteuerelemente des Browsers werden angezeigt und nicht der benutzerdefinierte Skin von Video.js.
* Dies beinhaltet die meisten Mobilgeräte (iOS, Android) und ältere Versionen von
* Safari.
*
* @param {Objekt} [Vollbildoptionen]
* Überschreibt die Vollbild-Optionen des Players
*
* @fires Player#fullscreenchange
* /
requestFullScreen (FullScreenOptions) {
const PromiseClass = this.options_.Promise || window.Promise;
if (PromiseClass) {
const self = this;
return new PromiseClass((resolve, reject) => {
function offHandler() {
self.off('fullscreenerror', errorHandler);
self.off('fullscreenchange', changeHandler);
}
function changeHandler() {
offHandler();
resolve();
}
function errorHandler(e, err) {
offHandler();
zurückweisen(err);
}
self.one('fullscreenchange', changeHandler);
self.one('fullscreenerror', errorHandler);
const promise = self.requestFullScreenHelper_ (FullScreenOptions);
if (Versprechen) {
promise.then(offHandler, offHandler);
promise.then(resolve, reject);
}
});
}
gib this.requestFullScreenHelper_ () zurück;
}
requestFullScreenHelper_ (FullScreenOptions) {
lass fsOptions;
//Übergeben Sie in spezifikationskonformen Browsern nur Vollbild-Optionen an requestFullScreen.
//Verwende die Standardeinstellungen oder die vom Spieler konfigurierte Option, sofern sie nicht direkt an diese Methode übergeben werden.
wenn (! this.fsapi_.Präfix) {
fsOptions = this.options_.fullscreen & this.options_.fullscreen.options || {};
wenn (FullScreenOptions! == undefiniert) {
fsOptions = Vollbildoptionen;
}
}
//Diese Methode funktioniert wie folgt:
//1. wenn eine Vollbild-API verfügbar ist, benutze sie
//1. requestFullScreen mit möglichen Optionen aufrufen
//2. Wenn wir ein Versprechen von oben bekommen haben, benutze es, um isFullScreen () zu aktualisieren
//2. Andernfalls, falls der Techniker den Vollbildmodus unterstützt, rufen Sie dort `enterFullScreen` auf.
//Dies wird insbesondere für iPhone, ältere iPads und Browser ohne Safari unter iOS verwendet.
//3. Verwenden Sie andernfalls den Modus „FullWindow“
if (this.fsApi_.requestFullscreen) {
const promise = this.el_ [this.fsapi_.requestFullScreen] (fsOptions);
if (Versprechen) {
promise.then () => this.isFullScreen (wahr), () => this.isFullScreen (falsch));
}
versprechen zurückgeben;
} else if (this.tech_.supportsFullScreen() && !this.options_.preferFullWindow === true) {
//Wir können die video.js Steuerelemente nicht im Vollbildmodus verwenden, aber wir können sie im Vollbildmodus verwenden
//mit nativen Steuerelementen
this.techCall_ ('Vollbild eingeben');
} sonst {
//Der Vollbildmodus wird nicht unterstützt, also dehnen wir das Videoelement einfach aus
//fülle das Viewport
this.enterFullWindow ();
}
}
/**
* Bringen Sie das Video auf die normale Größe zurück, nachdem Sie sich im Vollbildmodus befunden haben
*
* @fires Player#fullscreenchange
* /
ExitFullScreen () {
const PromiseClass = this.options_.Promise || window.Promise;
if (PromiseClass) {
const self = this;
return new PromiseClass((resolve, reject) => {
function offHandler() {
self.off('fullscreenerror', errorHandler);
self.off('fullscreenchange', changeHandler);
}
function changeHandler() {
offHandler();
resolve();
}
function errorHandler(e, err) {
offHandler();
zurückweisen(err);
}
self.one('fullscreenchange', changeHandler);
self.one('fullscreenerror', errorHandler);
const promise = self.exitFullScreenHelper_ ();
if (Versprechen) {
promise.then(offHandler, offHandler);
//Ordne das Versprechen unseren Lösungs-/Ablehnungsmethoden zu
promise.then(resolve, reject);
}
});
}
gib this.exitFullScreenHelper_ () zurück;
}
exitFullScreenHelper_ () {
if (this.fsApi_.requestFullscreen) {
const promise = dokument [this.fsapi_.exitFullScreen] ();
if (Versprechen) {
//Wir teilen das Versprechen hier auf, also wollen wir das
//potenzieller Fehler, damit diese Kette keine unbehandelten Fehler hat
silencePromise (promise.then () => this.isFullScreen (falsch)));
}
versprechen zurückgeben;
} else if (this.tech_.supportsFullScreen() && !this.options_.preferFullWindow === true) {
this.techCall_ ('Vollbild beenden');
} sonst {
this.exitFullWindow();
}
}
/**
* Wenn der Vollbildmodus nicht unterstützt wird, können wir den
* Videocontainer so breit, wie es der Browser zulässt.
*
* @fires Spieler #enterFullWindow
* /
Geben Sie FullWindow () ein {
this.isFullScreen (wahr);
this.isFullWindow = wahr;
//Speichern des ursprünglichen Doc-Overflow-Werts, zu dem zurückgekehrt werden soll, wenn der Vollbildmodus ausgeschaltet ist
this.DocOrigOverflow = document.documentElement.style.overflow;
//Füge einen Listener für die ESC-Taste hinzu, um den Vollbildmodus zu verlassen
events.on (document, 'keydown', this.boundFullWindowOnescKey_);
//Alle Scrollbalken ausblenden
document.documentElement.style.overflow = 'versteckt';
//Vollbildstile anwenden
dom.addClass (document.body, 'vjs-full window');
/**
* @event Spieler #enterFullWindow
* @Typ {EventTarget~Event}
* /
this.trigger ('EnterFullWindow');
}
/**
* Suchen Sie nach einem Anruf, um entweder das gesamte Fenster zu verlassen oder
* Vollbild auf ESC-Taste
*
* @param {string} Ereignis
* Ereignis, um zu überprüfen, ob die Taste gedrückt wurde
* /
FullWindowOnESCKey (Ereignis) {
if (keycode.isEventKey(event, 'Esc')) {
if (this.isFullScreen () === wahr) {
wenn (! this.isFullWindow) {
this.exitFullscreen();
} sonst {
this.exitFullWindow();
}
}
}
}
/**
* Vollständiges Fenster verlassen
*
* @fires Spieler #exitFullWindow
* /
exitFullWindow () {
this.isFullScreen (falsch);
this.isFullWindow = falsch;
Events.off(document, 'keydown', this.boundFullWindowOnEscKey_);
//Scrollbalken einblenden.
document.documentElement.style.overflow = this.DocOrigOverflow;
//Vollbildstile entfernen
dom.removeClass (document.body, 'vjs-full window');
//Ändere die Größe der Box, des Controllers und des Posters auf die Originalgröße
//this.positionAll ();
/**
* @event Spieler #exitFullWindow
* @Typ {EventTarget~Event}
* /
this.trigger ('exitFullWindow');
}
/**
* Deaktivieren Sie den Bild-im-Bild-Modus.
*
* @param {boolean} value
* - true deaktiviert den Bild-im-Bild-Modus
* - false aktiviert den Bild-im-Bild-Modus
* /
disablePictureInPicture (Wert) {
if (Wert === undefiniert) {
gib this.techGet_ ('disablePictureInPicture') zurück;
}
this.techCall_ ('setDisablePictureInPicture', Wert);
this.options_.disablePictureInPicture = Wert;
this.trigger ('Bild im Bild geändert deaktivieren');
}
/**
* Überprüfe, ob sich der Spieler im Bild-im-Bild-Modus befindet, oder teile dem Spieler mit, dass er
* ist im Bild-im-Bild-Modus oder nicht.
*
* @param {boolean} [ISPip]
* Stellen Sie den aktuellen Bild-im-Bild-Status des Spielers ein
*
* @return {boolean}
* - wahr, wenn Picture-in-Picture aktiviert ist und
* - falsch, wenn Picture-im-Picture ausgeschaltet ist und
* /
isinPictureInPicture (isPIP) {
wenn (ISPIP! == undefiniert) {
this.isInPictureInPicture_ =!! Ein Slip;
this.togglePictureClass_ ();
rückkehr;
}
kehre zurück!! Das. ist auf dem Bild in Bild _;
}
/**
* Erstellen Sie ein schwebendes Videofenster, das sich immer über anderen Fenstern befindet, so dass die Benutzer
* weiterhin Medien konsumieren, während sie mit anderen Inhaltsseiten interagieren, oder
* anwendungen auf ihrem Gerät.
*
* @see [Spec]{@link https://wicg.github.io/picture-in-picture}
*
* @fires Spieler #enterpictureinpicture
*
* @return {Versprechen}
* Ein Versprechen mit einem Picture-in-Picture-Fenster.
* /
requestPictureInPicture() {
if ('PictureInPictureEnabled' im Dokument && this.disablePictureInPicture () === false) {
/**
* Dieses Ereignis wird ausgelöst, wenn der Spieler den Bild-im-Bild-Modus betritt
*
* @event Spieler #enterpictureinpicture
* @Typ {EventTarget~Event}
* /
gib this.techGet_ ('requestPictureInPicture') zurück;
}
}
/**
* Beenden Sie den Bild-im-Bild-Modus.
*
* @see [Spec]{@link https://wicg.github.io/picture-in-picture}
*
* @fires Spieler #leavepictureinpicture
*
* @return {Versprechen}
* Ein Versprechen.
* /
ExitPictureInPicture () {
if ('PictureInPictureEnabled' im Dokument) {
/**
* Dieses Ereignis wird ausgelöst, wenn der Spieler das Bild im Bildmodus verlässt
*
* @event Spieler #leavepictureinpicture
* @Typ {EventTarget~Event}
* /
gib document.exitPictureInPicture () zurück;
}
}
/**
* Wird aufgerufen, wenn dieser Player den Fokus hat und eine Taste gedrückt wird, oder wenn
* Jede Komponente dieses Players erhält einen Tastendruck, den er nicht verarbeitet.
* Dies ermöglicht spielerweite Hotkeys (entweder wie unten definiert oder optional)
* durch eine externe Funktion).
*
* @param {EventTarget~Event} event
* Das "Keydown"-Ereignis, das zum Aufruf dieser Funktion geführt hat.
*
* @listens keydown
* /
handleKeyDown(event) {
const {userActions} = this.options_;
//Raus, wenn Hotkeys nicht konfiguriert sind.
wenn (! Benutzeraktionen ||! UserActions.Hotkeys) {
rückkehr;
}
//Funktion, die bestimmt, ob ein Element ausgeschlossen werden soll oder nicht
//Umgang mit Hotkeys.
const excludeElement = (de) => {
const tagName = el.tagName.toLowerCase ();
//Der erste und einfachste Test ist für `contenteditable` Elemente.
wenn (el.isContentEditable) {
true zurückgeben;
}
//Eingaben, die diesen Typen entsprechen, lösen weiterhin die Hotkey-Behandlung aus als
//es sind keine Texteingaben.
const allowedInputTypes = [
schaltfläche",
'Kästchen',
'versteckt',
'Funk',
'zurücksetzen',
'absenden'
];
if (TagName === 'Eingabe') {
return AllowedInputTypes.indexOf (el.type) === -1;
}
//Der letzte Test erfolgt anhand des Tag-Namens. Diese Tags werden vollständig ausgeschlossen.
const excludedTags = ['Textbereich'];
gib excludedTags.indexOf (tagName) zurück! = -1;
};
//Aussteigen, wenn sich der Benutzer auf ein interaktives Formularelement konzentriert.
wenn (excludeElement (this.el_.ownerDocument.activeElement)) {
rückkehr;
}
if (typeof UserActions.Hotkeys === 'Funktion') {
UserActions.Hotkeys.Call (dies, Ereignis);
} sonst {
this.handleHotKeys (Ereignis);
}
}
/**
* Wird aufgerufen, wenn dieser Spieler ein Hotkey-Keydown-Ereignis erhält.
* Unterstützte spielerweite Hotkeys sind:
*
* f - Vollbild umschalten
* m - schaltet die Stummschaltung ein
* k oder Space - schaltet zwischen Wiedergabe/Pause um
*
* @param {EventTarget~Event} event
* Das "Keydown"-Ereignis, das zum Aufruf dieser Funktion geführt hat.
* /
handleHotKeys (Ereignis) {
const Hotkeys = this.options_.UserActions? this.options_.userActions.Hotkeys: {};
//setze FullScreenKey, MuteKey, playPauseKey von `hotkeys`, verwende Standardwerte, falls nicht gesetzt
konstant {
fullScreenKey = keydownEvent => keycode.isEventKey (keydownEvent, 'f'),
muteKey = keydownEvent => keycode.isEventKey (keydownEvent, 'm'),
playPauseKey = KeydownEvent => (keyCode.ISEventKey (keydownEvent, 'k') || keycode.isEventKey (keydownEvent, 'Space'))
} = Tastenkombinationen;
if (fullScreenKey.call (this, event)) {
event.preventDefault();
event.stopPropagation();
const fsToggle = Component.getComponent ('fullScreenToggle');
if (document [this.fsapi_.FullScreenEnabled]! == falsch) {
fstoggle.prototype.handleClick.Call (dies, Ereignis);
}
} sonst wenn (muteKey.call (this, event)) {
event.preventDefault();
event.stopPropagation();
const muteToggle = Component.getComponent ('muteToggle');
muteToggle.prototype.handleClick.call (dies, Ereignis);
} sonst wenn (playPauseKey.call (this, event)) {
event.preventDefault();
event.stopPropagation();
const playToggle = Component.getComponent ('playToggle');
playToggle.prototype.handleClick.call (dies, Ereignis);
}
}
/**
* Prüfe, ob der Spieler einen bestimmten Mimetype spielen kann
*
* @see https://www.w3.org/TR/2011/WD-html5-20110113/video.html#dom-navigator-canplaytype
*
* @param {string} type
* Der zu prüfende Mimetyp
*
* @return {string}
* 'wahrscheinlich', 'vielleicht', oder '' (leere Zeichenfolge)
* /
canPlayType (Typ) {
können;
//Die einzelnen Wiedergabetechnologien in der Reihenfolge der Optionen durchspielen
für (sei i = 0, j = this.options_.techOrder; i < j.length; i++) {
const TechName = j [i];
let tech = Tech.getTech(techName);
// Unterstützung des alten Verhaltens, dass Techs als Komponenten registriert werden.
// Entfernen, sobald das veraltete Verhalten entfernt wird.
if (!tech) {
tech = Component.getComponent(techName);
}
// Prüfen Sie, ob der aktuelle Tech definiert ist, bevor Sie fortfahren
if (!tech) {
log.error(`Der "${techName}" tech ist undefiniert. Die Überprüfung der Browserunterstützung für diese Technologie wurde übersprungen");
weiter;
}
// Prüfen Sie, ob der Browser diese Technologie unterstützt
wenn (tech.isSupported ()) {
can = tech.canPlayType (Typ);
wenn (kann) {
zurückgeben können;
}
}
}
zurückgeben '';
}
/**
* Wählen Sie die Quelle basierend auf der technischen Reihenfolge oder der Quellreihenfolge
* Verwendet die Auswahl der Quellreihenfolge, wenn `options.sourceOrder` wahr ist. Andernfalls
* standardmäßig die Auswahl der technischen Reihenfolge
*
* @param {Array} Quellen
* Die Quellen für ein Medienelement
*
* @return {object|Boolean}
* Objekt der Quelle und technische Bestellung oder falsch
* /
SelectSource (Quellen) {
//Ruft nur die in `TechOrder` angegebenen Techniker ab, die existieren und von der unterstützt werden
//aktuelle Plattform
Const techs =
this.options_.techOrder
.map (TechName) => {
gib [TechName, Tech.getTech (TechName)] zurück;
})
.filter (([TechName, Technik]) => {
// Prüfen Sie, ob der aktuelle Tech definiert ist, bevor Sie fortfahren
wenn (Technik) {
// Prüfen Sie, ob der Browser diese Technologie unterstützt
gib tech.isSupported () zurück;
}
log.error(`Der "${techName}" tech ist undefiniert. Die Überprüfung der Browserunterstützung für diese Technologie wurde übersprungen");
return false;
});
//Iteriere jedes `innerArray`-Element einmal pro `outerArray`-Element und führe es aus
//`tester` mit beiden. Wenn `tester` einen nicht falschen Wert zurückgibt, beenden Sie das Programm vorzeitig und kehren Sie zurück
//dieser Wert.
const findFirstPassingTechSourcePair = Funktion (outerArray, innerArray, Tester) {
gefunden lassen;
outerArray.some (outerChoice) => {
gib innerArray.some ((innerChoice) => {zurück
gefunden = Tester (OuterChoice, InnerChoice);
wenn (gefunden) {
true zurückgeben;
}
});
});
Rückgabe gefunden;
};
lass SourceandTech gründen;
const flip = (fn) => (a, b) => fn (b, a);
const finder = ([TechName, tech], Quelle) => {
if (tech.canPlaySource (source, this.options_ [techname.toLowerCase ()]) {
return {Quelle, Technologie: TechName};
}
};
//Abhängig von der Richtigkeit von `options.sourceOrder` vertauschen wir die Reihenfolge der Techniker und Quellen
//um anhand ihrer Priorität aus ihnen auszuwählen.
wenn (this.options_.sourceOrder) {
//Reihenfolge an erster Stelle
foundSourceAndTech = findFirstPassingTechSourcePair (Quellen, Technologien, flip (Finder));
} sonst {
//Technisch erste Bestellung
FoundSourceAndTech = FindFirstPassingTechSourcePair (Techniker, Quellen, Finder);
}
gib foundSourceandTech zurück || falsch;
}
/**
* Führt die Quelleinstellung aus und ruft Logik ab
*
* @param {Tech~SourceObject|Tech~SourceObject[]|string} [Quelle]
* Ein SourceObject, ein Array von SourceObjects oder ein String, der auf
* eine URL zu einer Medienquelle. Es wird _höchst empfohlen_, dass ein Objekt
* oder Array von Objekten verwendet, so dass die Quellenauswahl
* algorithmen können den "Typ" berücksichtigen.
*
* Wenn nicht angegeben, fungiert diese Methode als Getter.
* @param {boolean} isRetry
* Zeigt an, ob dies intern als Ergebnis eines Wiederholungsversuchs aufgerufen wird
*
* @return {string|undefined}
* Wenn das Argument "Quelle" fehlt, wird die aktuelle Quelle zurückgegeben
* URL. Andernfalls gibt nichts zurück/undefined zurück.
* /
handlesRC_ (Quelle, isRetry) {
// Getter-Verwendung
if (Quelltyp === 'undefiniert') {
gib this.cache_.src zurück || „;
}
//Setzt das Wiederholungsverhalten für die neue Quelle zurück
wenn (this.resetRetryOnError_) {
this.resetRetryOnError_ ();
}
//filtere ungültige Quellen heraus und verwandle unsere Quelle in
//ein Array von Quellobjekten
const sources = FilterSource (Quelle);
//wenn eine Quelle übergeben wurde, ist sie ungültig, weil
//es wurde auf ein Array der Länge Null gefiltert. Also müssen wir
//zeige einen Fehler
if (!sources.length) {
this.setTimeout(function() {
this.error({ code: 4, message: this.options_.notSupportedMessage });
}, 0);
rückkehr;
}
//erste Quellen
this.changingSrc_ = true;
//Aktualisiere die zwischengespeicherte Quellliste nur, wenn wir nach einem Fehler nicht erneut versuchen, eine neue Quelle zu verwenden,
//da wir in diesem Fall die ausgefallene (n) Quelle (n) in den Cache aufnehmen wollen
if (!isRetry) {
this.cache_.sources = sources;
}
this.updateSourceCaches_ (Quellen [0]);
//MiddlewareSource ist die Quelle, nachdem sie durch Middleware geändert wurde
Middleware.setSource (this, sources [0], (MiddlewareSource, mws) => {
this.middleware_ = mws;
//da SourceSet asynchron ist, müssen wir den Cache erneut aktualisieren, nachdem wir eine Quelle ausgewählt haben, da
//Die ausgewählte Quelle könnte aufgrund des Cache-Updates über diesem Callback nicht in Ordnung sein.
if (!isRetry) {
this.cache_.sources = sources;
}
this.updateSourceCaches_ (Middleware-Quelle);
const err = this.src_ (MiddlewareSource);
if (err) {
wenn (sources.length > 1) {
gib this.handlesRC_ (sources.slice (1)) zurück;
}
this.changingSrc_ = false;
//Wir müssen das in ein Timeout einbauen, um den Leuten die Möglichkeit zu geben, Fehler-Event-Handler hinzuzufügen
this.setTimeout(function() {
this.error({ code: 4, message: this.options_.notSupportedMessage });
}, 0);
//wir konnten keinen passenden Techniker finden, aber lassen Sie uns den Delegierten trotzdem benachrichtigen, dass dies der richtige ist
//das braucht einen besseren Kommentar dazu, warum das nötig ist
this.triggerReady();
rückkehr;
}
Middleware.setTech (mws, this.tech_);
});
//Versuche es mit einer anderen verfügbaren Quelle, falls diese vor der Wiedergabe fehlschlägt.
wenn (this.options_.retryOnError && sources.length > 1) {
konstante Wiederholung = () => {
//Entferne das Fehlermodal
this.error(null);
this.handlesRC_ (sources.slice (1), wahr);
};
const stopListeningForErrors = () => {
this.off('error', retry);
};
this.one ('Fehler', erneut versuchen);
this.one ('spielt', stoppListeningForErrors);
this.resetRetryOnError_ = () => {
this.off('error', retry);
this.off ('wird abgespielt', stoppListeningForErrors);
};
}
}
/**
* Holen Sie sich die Videoquelle oder stellen Sie sie ein.
*
* @param {Tech~SourceObject|Tech~SourceObject[]|string} [Quelle]
* Ein SourceObject, ein Array von SourceObjects oder ein String, der auf
* eine URL zu einer Medienquelle. Es wird _höchst empfohlen_, dass ein Objekt
* oder Array von Objekten verwendet, so dass die Quellenauswahl
* algorithmen können den "Typ" berücksichtigen.
*
* Wenn nicht angegeben, fungiert diese Methode als Getter.
*
* @return {string|undefined}
* Wenn das Argument "Quelle" fehlt, wird die aktuelle Quelle zurückgegeben
* URL. Andernfalls gibt nichts zurück/undefined zurück.
* /
src (Quelle) {
gib this.handlesRC_ zurück (Quelle, falsch);
}
/**
* Setzt das Quellobjekt auf die Technologie, gibt einen booleschen Wert zurück, der angibt, ob
* Es gibt eine Technologie, die die Quelle abspielen kann oder nicht
*
* @param {Tech~SourceObject} source
* Das Quellobjekt, das auf dem Tech gesetzt werden soll
*
* @return {boolean}
* - Stimmt, wenn es keine Technologie gibt, um diese Quelle abzuspielen
* - Falsch sonst
*
* @privat
* /
src_ (Quelle) {
const sourceTech = this.selectSource ([Quelle]);
wenn (! SourceTech) {
true zurückgeben;
}
wenn (! titleCaseEquals (sourceTech.tech, this.techName_) {
this.changingSrc_ = true;
//lade diese Technologie mit der ausgewählten Quelle
this.loadtech_ (Quelltech.tech, Quelltech.Quelle);
this.tech_.ready () => {
this.changingSrc_ = false;
});
return false;
}
//warte, bis der Techniker bereit ist, die Quelle einzustellen
//und stelle es wenn möglich synchron ein (#2326)
this.ready(function() {
//Die setSource-Tech-Methode wurde mit Quellhandlern hinzugefügt
//also werden ältere Techniker es nicht unterstützen
//Wir müssen den direkten Prototyp für den Fall überprüfen, in dem Unterklassen
//der Technologie unterstützt keine Quellcodehandler
wenn (this.tech_.constructor.prototype.hasOwnProperty ('setSource')) {
this.techCall_ ('setSource', Quelle);
} sonst {
this.techCall_ ('src', source.src);
}
this.changingSrc_ = false;
}, true);
return false;
}
/**
* Beginne mit dem Laden der src-Daten.
* /
laden () {
this.techCall_ ('laden');
}
/**
* Setze den Player zurück. Lädt die erste Technologie im TechOrder,
* entfernt alle Textspuren im existierenden `tech`,
* und ruft `reset` auf dem `tech` auf.
* /
reset() {
const PromiseClass = this.options_.Promise || window.Promise;
wenn (this.paued () ||! PromiseClass) {
Das.doReset_ ();
} sonst {
const playPromise = this.play ();
silencePromise (playPromise.then () => this.doReset_ ());
}
}
oder Reset_ () {
if (this.tech_) {
this.tech_.clearTracks ('text');
}
this.resetCache_();
diese.poster („);
this.loadTech_ (this.options_.techOrder [0], null);
this.techCall_ ('zurücksetzen');
this.resetControlBarUI_ ();
if (isEvented(this)) {
this.trigger ('playerreset');
}
}
/**
* Setze die Benutzeroberfläche der Control Bar zurück, indem du Untermethoden aufrufst, die das Zurücksetzen
* alle Komponenten der Control Bar
* /
resetControlBarUI_ () {
this.resetProgressBar_ ();
this.resetPlaybackRate_ ();
this.resetVolumeBar_ ();
}
/**
* Setze den Fortschritt der Technik zurück, sodass der Fortschrittsbalken in der Benutzeroberfläche zurückgesetzt wird
* /
resetProgressBar_ () {
this.currentTime(0);
const {DurationDisplay, RemainingTimeDisplay} = this.controlBar || {};
wenn (DurationDisplay) {
Dauer Display.updateContent ();
}
wenn (RemainingTimeDisplay) {
Verbleibende Zeit Display.updateContent ();
}
}
/**
* Wiedergabeverhältnis zurücksetzen
* /
Wiedergaberate zurücksetzen_ () {
this.playbackRate (this.defaultPlaybackRate ());
this.handleTechRateChange_ ();
}
/**
* Lautstärkeleiste zurücksetzen
* /
ResetVolumeBar_ () {
diese.volume (1.0);
this.trigger ('Volumenänderung');
}
/**
* Gibt alle aktuellen Quellobjekte zurück.
*
* @return {Tech~SourceObject[]}
* Die aktuellen Quellobjekte
* /
Aktuelle Quellen () {
const source = this.currentSource ();
konstante Quellen = [];
//gehe von `{}` oder `{src}` aus
if (Object.keys (source) .length! == 0) {
sources.push (Quelle);
}
gib this.cache_.sources || sources zurück;
}
/**
* Gibt das aktuelle Quellobjekt zurück.
*
* @return {Tech~SourceObject}
* Das aktuelle Quellobjekt
* /
Aktuelle Quelle () {
gib this.cache_.source zurück || {};
}
/**
* Gibt die vollständig qualifizierte URL des aktuellen Quellwerts zurück, z. B. http://mysite.com/video.mp4
* Kann in Verbindung mit `CurrentType` verwendet werden, um beim Neuaufbau des aktuellen Quellobjekts zu helfen.
*
* @return {string}
* Die aktuelle Quelle
* /
currentSrc() {
gib this.currentSource () && this.currentSource () .src || „;
}
/**
* Ruft den aktuellen Quelltyp ab, z. B. Video/MP4
* Dadurch können Sie das aktuelle Quellobjekt neu erstellen, sodass Sie es laden können
* Quelle und Technik später
*
* @return {string}
* Der Quell-MIME-Typ
* /
Aktueller Typ () {
gib this.currentSource () && this.currentSource () .type || „;
}
/**
* Holen Sie sich das Preload-Attribut oder legen Sie es fest
*
* @param {boolean} [Wert]
* - wahr bedeutet, dass wir vorladen sollten
* - falsch bedeutet, dass wir nicht vorladen sollten
*
* @return {string}
* Der Preload-Attributwert beim Abrufen
* /
Vorspannung (Wert) {
if (Wert !== undefiniert) {
this.techCall_ ('setPreload', Wert);
this.options_.preload = Wert;
rückkehr;
}
gib this.techGet_ ('preload') zurück;
}
/**
* Rufen Sie die Autoplay-Option ab oder stellen Sie sie ein. Wenn das ein boolescher Wert ist, wird es
* modifizieren Sie das Attribut der Technologie. Wenn dies eine Zeichenfolge ist, ist das Attribut auf
* Die Technologie wird entfernt und `Player` kümmert sich um das Autoplay bei Ladestarts.
*
* @param {boolean|Zeichenfolge} [Wert]
* - wahr: Autoplay mithilfe des Browserverhaltens
* - falsch: nicht automatisch abspielen
* - 'play': rufe play () bei jedem Ladestart auf
* - 'muted': rufe muted () auf und spiele () bei jedem Ladestart
* - 'any': rufe play () bei jedem Ladestart auf. Wenn das fehlschlägt, rufe muted () und dann play () auf.
* - *: Bei anderen als den hier aufgelisteten Werten wird `autoplay` auf true gesetzt
*
* @return {booles|Zeichenfolge}
* Der aktuelle Wert von Autoplay beim Abrufen
* /
Autoplay (Wert) {
// Getter-Verwendung
if (Wert === undefiniert) {
gib this.options_.autoplay || false zurück;
}
lass TechAutoplay;
//wenn der Wert ein gültiger String ist, setze ihn darauf oder normalisiere `true` auf 'play', falls nötig
if (typeof value === 'string' && (/(any|play|muted)/) .test (value) || value === true && this.options_.normalizeAutoplay) {
this.options_.autoplay = Wert;
this.manualAutoPlay_ (Wertetyp === 'Zeichenfolge'? Wert: 'abspielen');
TechAutoplay = falsch;
//Jeder falsche Wert setzt Autoplay im Browser auf Falsch,
//lass uns das Gleiche machen
} sonst wenn (! Wert) {
this.options_.autoplay = falsch;
//Jeder andere Wert (also wahr) setzt Autoplay auf true
} sonst {
this.options_.autoplay = wahr;
}
TechAutoplay = Typ von TechAutoPlay === 'undefiniert'? this.options_.autoplay: TechAutoPlay;
//wenn wir keinen Techniker haben, stehen wir nicht in der Warteschlange
//ein setAutoPlay-Aufruf bei tech ready. Wir machen das, weil
//Die Autoplay-Option wird im Konstruktor übergeben und wir
//muss nicht zweimal gesetzt werden
if (this.tech_) {
this.techCall_ ('setAutoplay', TechAutoPlay);
}
}
/**
* Setzt das playsinline-Attribut oder entfernt es.
* Playsinline teilt dem Browser mit, dass die Wiedergabe nicht im Vollbildmodus bevorzugt wird.
*
* @param {boolean} [Wert]
* - true bedeutet, dass wir standardmäßig versuchen sollten, Inline zu spielen
* - false bedeutet, dass wir den Standard-Wiedergabemodus des Browsers verwenden sollten,
* was in den meisten Fällen Inline ist. iOS Safari ist eine bemerkenswerte Ausnahme
* und spielt standardmäßig im Vollbildmodus ab.
*
* @return {string|Spieler}
* - der aktuelle Wert von playsinline
* - den Player bei der Einstellung
*
* @see [Spec]{@link https://html.spec.whatwg.org/#attr-video-playsinline}
* /
playsinline (Wert) {
if (Wert !== undefiniert) {
this.techCall_ ('setPlaysInLine', Wert);
this.options_.playsinline = Wert;
dies zurückgeben;
}
gib this.techGet_ ('playsinline') zurück;
}
/**
* Ruft das Loop-Attribut für das Videoelement ab oder legt es fest.
*
* @param {boolean} [Wert]
* - wahr bedeutet, dass wir das Video in einer Endlosschleife abspielen sollten
* - falsch bedeutet, dass wir das Video nicht in einer Endlosschleife abspielen sollten
*
* @return {boolean}
* Der aktuelle Wert von Loop beim Abrufen
* /
Schleife (Wert) {
if (Wert !== undefiniert) {
this.techCall_ ('setLoop', Wert);
this.options_.loop = Wert;
rückkehr;
}
gib this.techGet_ ('loop') zurück;
}
/**
* Rufen Sie die Quell-URL für das Posterbild ab oder legen Sie sie fest
*
* @fires Player#Plakatwechsel
*
* @param {Zeichenfolge} [src]
* Quell-URL des Posterbilds
*
* @return {string}
* Der aktuelle Wert des Posters beim Kauf
* /
plakat (src) {
if (src === undefiniert) {
gib this.poster_ zurück;
}
//Der richtige Weg, ein Poster zu entfernen, besteht darin, es als leere Zeichenfolge zu setzen
//andere falsche Werte lösen Fehler aus
if (!src) {
src = „;
}
if (src === this.poster_) {
rückkehr;
}
//aktualisiere die interne Poster-Variable
this.poster_ = src;
//aktualisiere das Technologie-Poster
this.techCall_ ('setPoster', src);
this.isPosterFromTech_ = false;
//Komponenten darauf aufmerksam machen, dass das Poster gesetzt wurde
/**
* Dieses Event wird ausgelöst, wenn das Posterbild auf dem Player geändert wird.
*
* @event Spieler #posterchange
* @Typ {EventTarget~Event}
* /
this.trigger('posterchange');
}
/**
* Einige Techniker (z. B. YouTube) können eine Posterquelle in einem
* asynchroner Weg. Wir möchten, dass die Poster-Komponente dies verwendet
* Quelltext als Poster, um die Kontrollen der Technologie zu vertuschen.
* (Die Play-Schaltfläche von YouTube). Wir wollen dies jedoch nur verwenden.
* Quelle falls der Player-User kein Poster durchgestellt hat
* die normalen APIs.
*
* @fires Player#Plakatwechsel
* @listens Technik #posterchange
* @privat
* /
handleTechPosterChange_ () {
wenn ((! this.poster_ | this.options_.techCanOverridePoster) & this.tech_ & this.tech_.poster) {
const newPoster = this.tech_.poster () || „;
wenn (NewPoster! == dieses.Poster_) {
this.poster_ = Neues Poster;
this.isPosterFromTech_ = wahr;
//Lass die Komponenten wissen, dass sich das Poster geändert hat
this.trigger('posterchange');
}
}
}
/**
* Ermittelt oder legt fest, ob die Steuerelemente angezeigt werden oder nicht.
*
* @fires Spieler #controlsenabled
*
* @param {boolean} [bool]
* - wahr, um die Steuerung einzuschalten
* - Falsch, um die Steuerung auszuschalten
*
* @return {boolean}
* Der aktuelle Wert der Kontrollen beim Abrufen
* /
Steuerelemente (bool) {
if (bool === undefiniert) {
kehre zurück!! this.controls_;
}
bool = !!bool;
// Kein Änderungsereignis auslösen, wenn es sich nicht tatsächlich geändert hat
wenn (this.controls_ === bool) {
rückkehr;
}
this.controls_ = bool;
wenn (this.usingNativeControls ()) {
this.techCall_ ('setControls', bool);
}
wenn (this.controls_) {
this.removeClass ('vjs-controls-disabled');
this.addClass('vjs-controls-enabled');
/**
* @event Spieler #controlsenabled
* @Typ {EventTarget~Event}
* /
this.trigger ('Steuerelemente aktiviert');
if (!this.usingNativeControls()) {
this.addTechControlsListeners_();
}
} sonst {
this.removeClass ('vjs-controls-enabled');
this.addClass('vjs-controls-disabled');
/**
* @event Spieler #controlsdisabled
* @Typ {EventTarget~Event}
* /
this.trigger ('Steuerung deaktiviert');
if (!this.usingNativeControls()) {
this.removeTechControlsListeners_();
}
}
}
/**
* Schaltet die nativen Steuerungen ein/aus. Native Steuerelemente sind die integrierten Steuerelemente
* Geräte (z. B. Standard-iPhone-Steuerungen) oder andere Technologien
* (z. B. Vimeo Controls)
* **Dies sollte nur durch den aktuellen Techniker festgelegt werden, da nur der Techniker es weiß
* ob es native Steuerelemente unterstützen kann**
*
* @fires Spieler #usingnativecontrols
* @fires Spieler #usingcustomcontrols
*
* @param {boolean} [bool]
* - true, um die nativen Steuerelemente zu aktivieren
* - false, um native Steuerelemente auszuschalten
*
* @return {boolean}
* Der aktuelle Wert nativer Steuerelemente beim Abrufen
* /
Verwenden von NativeControls (bool) {
if (bool === undefiniert) {
kehre zurück!! Das. using NativeControls_;
}
bool = !!bool;
// Kein Änderungsereignis auslösen, wenn es sich nicht tatsächlich geändert hat
wenn (this.UsingNativeControls_ === bool) {
rückkehr;
}
this.UsingNativeControls_ = bool;
wenn (this.UsingNativeControls_) {
this.addClass ('vjs-using-native-controls');
/**
* Der Player verwendet die native Gerätesteuerung
*
* @event Spieler #usingnativecontrols
* @Typ {EventTarget~Event}
* /
this.trigger ('native Steuerelemente verwenden');
} sonst {
this.removeClass ('vjs-using-native-controls');
/**
* Der Spieler verwendet die benutzerdefinierten HTML-Steuerelemente
*
* @event Spieler #usingcustomcontrols
* @Typ {EventTarget~Event}
* /
this.trigger ('benutzerdefinierte Steuerelemente verwenden');
}
}
/**
* Setze oder erhalte den aktuellen MediaError
*
* @fires Spieler #error
*
* @param {mediaError|string|Zahl} [Fehler]
* Ein MediaError oder eine Zeichenkette/Zahl, die umgewandelt werden soll
* in einen MediaError
*
* @return {MediaError|null}
* Der aktuelle MediaError beim Abrufen von (oder null)
* /
error(err) {
if (err === undefiniert) {
gib this.error_ || null; zurück
}
//erlaube Hooks, das Fehlerobjekt zu modifizieren
haken ('beforeerror') .forEach ((hookFunction) => {
const newErr = hookFunction (das, err);
wenn (! (
(isObject (newErr) &&! Array.isArray (neuere Version) |
typeof newErr === 'Zeichenfolge' ||
typeof newErr === 'Zahl' ||
Neuerer R === null
) {
this.log.error ('Bitte gib einen Wert zurück, den MediaError in den Beforeerror−Hooks erwartet');
rückkehr;
}
err = neuerer RR;
});
//Unterdrückt die erste Fehlermeldung für keine kompatible Quelle bis
//Benutzerinteraktion
if (this.options_.suppressNotSupportedError &&
Fehler & Fehlercode === 4
) {
const triggerSuppressedError = Funktion () {
this.error (Fehler);
};
this.options_.suppressNotSupportedError = falsch;
this.any (['click', 'touchstart'], triggerSuppressedError);
this.one ('loadstart', function () {
this.off (['click', 'touchstart'], triggerSuppressedError);
});
rückkehr;
}
//auf Standard zurücksetzen
wenn (Fehler === null) {
this.error_ = Fehler;
this.removeClass ('vjs-Fehler');
wenn (this.errorDisplay) {
this.errorDisplay.close ();
}
rückkehr;
}
this.error_ = new MediaError(err);
//füge dem Player den vjs-error-Klassennamen hinzu
this.addClass ('vjs-Fehler');
//protokolliert den Namen des Fehlertyps und jede Nachricht
//IE11 protokolliert „[Object Object]“ und forderte Sie auf, die Nachricht zu erweitern, um das Fehlerobjekt zu sehen
log.error (`(CODE: $ {this.error_.code} $ {mediaError.errorTypes [this.error_.code]})`, this.error_.message, this.error_);
/**
* @event Spieler #error
* @Typ {EventTarget~Event}
* /
this.trigger('error');
//Hooks über den Fehler pro Spieler benachrichtigen
hooks ('Fehler') .forEach ((hookFunction) => hookFunction (dies, diese.error_));
rückkehr;
}
/**
* Benutzeraktivität melden
*
* @param {Object} event
* Event-Objekt
* /
reportUserActivity (Ereignis) {
this.userActivity_ = true;
}
/**
* Abrufen/setzen, ob der Benutzer aktiv ist
*
* @fires Spieler #useractive
* @fires Spieler #userinactive
*
* @param {boolean} [bool]
* - wahr, wenn der Benutzer aktiv ist
* - falsch, wenn der Benutzer inaktiv ist
*
* @return {boolean}
* Der aktuelle Wert von UserActive beim Abrufen
* /
userActive (bool) {
if (bool === undefiniert) {
gib this.UserActive_; zurück
}
bool = !!bool;
if (bool === this.UserActive_) {
rückkehr;
}
this.UserActive_ = bool;
wenn (this.userActive_) {
this.userActivity_ = true;
this.removeClass ('vjs-user-inactive');
this.addClass ('vjs-user-active');
/**
* @event Spieler #useractive
* @Typ {EventTarget~Event}
* /
this.trigger ('useractive');
rückkehr;
}
//Chrome/Safari/IE hat Fehler, bei denen das Ändern des Cursors möglich ist
//löst ein Mousemove-Ereignis aus. Dies verursacht ein Problem, wenn Sie sich verstecken.
//der Cursor, wenn der Benutzer inaktiv ist, und eine Mausbewegung signalisiert dem Benutzer
//Aktivität. Es ist unmöglich, in den inaktiven Modus zu wechseln. Konkret
//Das passiert im Vollbildmodus, wenn wir den Cursor wirklich verstecken müssen.
// //
//Wenn das in ALLEN Browsern behoben ist, kann es entfernt werden
//https://code.google.com/p/chromium/issues/detail?id=103041
if (this.tech_) {
this.tech_.one ('mousemove', Funktion (e) {
e. stopPropagation ();
e.preventDefault ();
});
}
this.userActivity_ = false;
this.removeClass ('vjs-user-active');
this.addClass ('vjs-user-inactive');
/**
* @event Spieler #userinactive
* @Typ {EventTarget~Event}
* /
this.trigger ('userinactive');
}
/**
* Anhand des Timeout-Werts auf Benutzeraktivitäten achten
*
* @privat
* /
ListenForUserActivity _ () {
lass die Maus laufen;
lass LastMoveX;
lass LastMovey;
const handleActivity = fn.Bind (this, this.reportUserActivity);
const handleMouseMove = Funktion (e) {
//#1068 - Beugt Mousemove-Spamming vor
//Chrome-Fehler: https://code.google.com/p/chromium/issues/detail?id=366970
wenn (e.ScreenX! == LastMoveX | e.SCREENY! == Letzter Film) {
LastMoveX = e.ScreenX;
LastMovey = e.Screeny;
handleActivity();
}
};
const handleMouseDown = Funktion () {
handleActivity();
// Solange sie das Gerät berühren oder die Maus gedrückt halten,
// Wir betrachten sie als aktiv, auch wenn sie ihren Finger oder ihre Maus nicht bewegen.
// Wir wollen also weiterhin aktualisieren, dass sie aktiv sind
this.clearInterval(mouseInProgress);
//UserActivity=True jetzt setzen und das Intervall auf die gleiche Zeit setzen
//da das ActivityCheck-Intervall (250) sicherstellen sollte, dass wir das nie verpassen
//nächster ActivityCheck
mouseinProgress = this.setInterval (handleActivity, 250);
};
const handleMouseUpAndMouseLeave = Funktion (Ereignis) {
handleActivity();
//Stoppt das Intervall, in dem die Aktivität aufrechterhalten wird, wenn die Maus/Berührung ausgeschaltet ist
this.clearInterval(mouseInProgress);
};
//Jede Mausbewegung wird als Benutzeraktivität betrachtet
this.on ('mousedown', handleMouseDown);
this.on ('mousemove', handleMouseMove);
this.on ('mouseup', handleMouseUp und MouseLeave);
this.on ('mouseleave', handleMouseUp und Mouseleave);
const ControlBar = this.getChild ('ControlBar');
//Behebt einen Fehler auf Android und iOS, bei dem beim Tippen auf ProgressBar (wenn die Kontrollleiste angezeigt wird)
//ControlBar würde standardmäßig nicht mehr ausgeblendet sein.
wenn (ControlBar &&! Browser.is_iOS &&! Browser.is_Android) {
ControlBar.on ('mouseenter', function (event) {
if (this.player () .options_.inactivityTimeout! == 0) {
this.player () .cache_.inactivityTimeout = this.player () .options_.inactivityTimeout;
}
this.player () .options_.InactivityTimeout = 0;
});
controlBar.on ('mouseleave', Funktion (Ereignis) {
this.player () .options_.inactivityTimeout = this.player () .cache_.inactivityTimeout;
});
}
//Achte auf die Tastaturnavigation
//Sollte das InProgress-Intervall wegen der Tastenwiederholung nicht verwenden müssen
this.on ('keydown', handleActivity);
this.on ('keyup', handleActivity);
//Führe alle 250 Millisekunden ein Intervall aus, anstatt alles reinzustopfen
//die Mousemove/Touchmove-Funktion selbst, um Leistungseinbußen zu verhindern.
//`this.reportUserActivity` setzt this.userActivity_ einfach auf true, was
//wird dann von dieser Schleife aufgenommen
//http://ejohn.org/blog/learning-from-twitter/
lass InactivityTimeout;
this.setInterval (Funktion () {
//Überprüfe, ob eine Maus-/Touch-Aktivität stattgefunden hat
if (!this.userActivity_) {
rückkehr;
}
//Setze den Aktivitätstracker zurück
this.userActivity_ = false;
//Wenn der Benutzerstatus inaktiv war, setzen Sie den Status auf aktiv
this.userActive(true);
//Löscht ein vorhandenes Inaktivitäts-Timeout, um den Timer erneut zu starten
this.clearTimeout (InactivityTimeout);
const timeout = this.options_.InactivityTimeout;
wenn (timeout <= 0) {
rückkehr;
}
//In <timeout> Millisekunden, wenn keine Aktivität mehr stattgefunden hat
//Der Benutzer wird als inaktiv betrachtet
inactivityTimeout = this.setTimeout (function () {
//Schützen Sie sich vor dem Fall, dass der InactivityTimeout nur ausgelöst werden kann
//bevor die nächste Benutzeraktivität von der Aktivitätscheckschleife aufgenommen wird
//verursacht ein Flackern
if (!this.userActivity_) {
this.userActive (falsch);
}
}, timeout);
}, 250);
}
/**
* Ruft die aktuelle Wiedergabegeschwindigkeit ab oder legt sie fest. Eine Wiedergabegeschwindigkeit von
* 1,0 steht für normale Geschwindigkeit und 0,5 würde für halbe Geschwindigkeit stehen
* Wiedergabe zum Beispiel.
*
* @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-playbackrate
*
* @param {Zahl} [Rate]
* Neue Wiedergabegeschwindigkeit zum Einstellen.
*
* @return {number}
* Die aktuelle Wiedergabegeschwindigkeit beim Abrufen von oder 1,0
* /
PlaybackRate (Rate) {
if (rate !== undefined) {
//HINWEIS: this.cache_.lastPlaybackRate wird vom Tech-Handler gesetzt
//das ist oben registriert
this.techCall_ ('setPlaybackRate', rate);
rückkehr;
}
if (this.tech_ && this.tech_.featuresPlaybackRate) {
gib this.cache_.lastPlaybackRate || this.techGet_ ('playbackRate') zurück;
}
1,0 zurück;
}
/**
* Ruft die aktuelle Standardwiedergaberate ab oder legt sie fest. Eine Standardwiedergaberate von
* 1,0 steht beispielsweise für eine normale Geschwindigkeit und 0,5 für eine Wiedergabe mit halber Geschwindigkeit.
* DefaultPlaybackRate gibt nur an, wie hoch die anfängliche PlaybackRate eines Videos war, nicht
* nicht die aktuelle PlaybackRate.
*
* @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-defaultplaybackrate
*
* @param {Zahl} [Rate]
* Neue Standardwiedergaberate zum Einstellen.
*
* @return {Nummer|Spieler}
* - Die Standard-Wiedergabegeschwindigkeit beim Abrufen von oder 1.0
* - den Player bei der Einstellung
* /
defaultPlaybackRate (Rate) {
if (rate !== undefined) {
gib this.techCall_ ('setDefaultPlaybackRate', rate) zurück;
}
if (this.tech_ && this.tech_.featuresPlaybackRate) {
gib this.techGet_ ('defaultPlaybackRate') zurück;
}
1,0 zurück;
}
/**
* Ruft das Audio-Flag ab oder setzt es
*
* @param {boolean} bool
* - true signalisiert, dass es sich um einen Audioplayer handelt
* - falsch signalisiert, dass es sich nicht um einen Audioplayer handelt
*
* @return {boolean}
* Der aktuelle Wert von isAudio beim Abrufen
* /
isAudio (bool) {
wenn (bool! == undefiniert) {
this.isAudio_ =!! boolen;
rückkehr;
}
kehre zurück!! Das.isAudio_;
}
EnableAudioOnlyUI_ () {
//Aktualisiere das Styling sofort, um die Kontrollleiste anzuzeigen, damit wir ihre Höhe ermitteln können
this.addClass ('vjs-Nur-Audio-Modus');
const playerChildren = this.children ();
const ControlBar = this.getChild ('ControlBar');
const ControlBarHeight = ControlBar & ControlBar.currentHeight ();
//Verstecke alle Player-Komponenten außer der Kontrollleiste. Komponenten der Steuerleiste
//werden nur für Videos benötigt, die mit CSS ausgeblendet werden
PlayerChildren.forEach (Kind => {
wenn (Kind === ControlBar) {
rückkehr;
}
wenn (child.el_ &&! child.hasClass ('vjs-hidden')) {
kind.hide ();
this.audioOnlyCache_.hiddenChildren.push (Kind);
}
});
this.audioOnlyCache_.playerHeight = this.currentHeight ();
//Stelle die Höhe des Spielers genauso ein wie in der Kontrollleiste
this.height (ControlBarHeight);
this.trigger('audioonlymodechange');
}
disableAudioOnlyUI_ () {
this.removeClass ('vjs-Nur-Audio-Modus');
//Spielerkomponenten anzeigen, die zuvor ausgeblendet waren
this.audioOnlyCache_.hiddenChildren.forEach (kind => child.show ());
//Spielergröße zurücksetzen
this.height (this.AudioOnlyCache_.playerHeight);
this.trigger('audioonlymodechange');
}
/**
* Ruft den aktuellen AudioOnlyMode-Status ab oder setzt AudioOnlyMode auf true oder false.
*
* Wenn Sie diesen Wert auf `true` setzen, werden alle Player-Komponenten außer der Kontrollleiste ausgeblendet,
* sowie Steuerleistenkomponenten, die nur für Video benötigt werden.
*
* @param {boolean} [Wert]
* Der Wert, auf den AudioOnlyMode gesetzt werden soll.
*
* @return {Promise|boolean}
* Ein Versprechen wird zurückgegeben, wenn der Status gesetzt wird, und ein boolescher Wert, wenn der Status gesetzt wird
* der gegenwärtige Zustand
* /
AudioOnlyMode (Wert) {
if (Art des Wertes! == 'boolean' || Wert === this.AudioOnlyMode_) {
gib this.AudioOnlyMode_ zurück;
}
this.AudioOnlyMode_ = Wert;
const PromiseClass = this.options_.Promise || window.Promise;
if (PromiseClass) {
//Aktiviere den Modus „Nur Audio“
wenn (Wert) {
const exitPromises = [];
//Fullscreen und PiP werden in AudioOnlyMode nicht unterstützt, also beenden Sie es, wenn nötig.
if (this.isInPictureInPicture()) {
exitPromises.push (this.exitPictureInPicture ());
}
if (this.isFullscreen()) {
exitPromises.push (this.exitFullScreen ());
}
wenn (this.AudioPosterMode ()) {
exitPromises.push (this.AudioPosterMode (falsch));
}
return PromiseClass.all (exitPromises) .then () => this.enableAudioOnlyUI_ ());
}
//Deaktiviere den Modus „Nur Audio“
return promiseClass.resolve () .then () => this.disableAudioOnlyUI_ ());
}
wenn (Wert) {
if (this.isInPictureInPicture()) {
this.exitPictureInPicture ();
}
if (this.isFullscreen()) {
this.exitFullscreen();
}
this.enableAudioOnlyUI_ ();
} sonst {
this.disableAudioOnlyUI_ ();
}
}
EnablePosterModeUI_ () {
//Verstecken Sie das Videoelement und zeigen Sie das Posterbild an, um PosterModeUI zu aktivieren
const tech = this.tech_ && this.tech_;
tech.hide ();
this.addClass ('vjs-audio-poster-mode');
this.trigger('audiopostermodechange');
}
deaktiviere PosterModeUI_ () {
//Zeige das Videoelement und blende das Posterbild aus, um PosterModeUI zu deaktivieren
const tech = this.tech_ && this.tech_;
tech.show ();
this.removeClass ('vjs-audio-poster-mode');
this.trigger('audiopostermodechange');
}
/**
* Ruft den aktuellen AudioPosterMode-Status ab oder setzt AudioPosterMode auf true oder false
*
* @param {boolean} [Wert]
* Der Wert, auf den AudioPosterMode gesetzt werden soll.
*
* @return {Promise|boolean}
* Ein Versprechen wird zurückgegeben, wenn der Status gesetzt wird, und ein boolescher Wert, wenn der Status gesetzt wird
* der gegenwärtige Zustand
* /
AudioPosterMode (Wert) {
if (Art des Wertes! == 'boolean' || Wert === this.AudioPosterMode_) {
gib this.AudioPosterMode_ zurück;
}
this.AudioPosterMode_ = Wert;
const PromiseClass = this.options_.Promise || window.Promise;
if (PromiseClass) {
wenn (Wert) {
if (this.audioOnlyMode()) {
const AudioOnlyModePromise = this.AudioOnlyMode (falsch);
gib AudioOnlyModePromise.then () => {
//aktiviere den Audio-Poster-Modus, nachdem der Nur-Audiomodus deaktiviert wurde
this.enablePosterModeUI_();
});
}
return PromiseClass.resolve().then(() => {
//aktiviere den Audio-Poster-Modus
this.enablePosterModeUI_();
});
}
return PromiseClass.resolve().then(() => {
//Deaktiviere den Audio-Poster-Modus
this.disablePosterModeUI_();
});
}
wenn (Wert) {
if (this.audioOnlyMode()) {
this.audioOnlyMode (falsch);
}
this.enablePosterModeUI_();
rückkehr;
}
this.disablePosterModeUI_();
}
/**
* Eine Hilfsmethode zum Hinzufügen eines {@link TextTrack} zu unserem
* {@link TextTrackList}.
*
* Zusätzlich zu den W3C-Einstellungen ermöglichen wir das Hinzufügen zusätzlicher Informationen über Optionen.
*
* @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-addtexttrack
*
* @param {Zeichenfolge} [Art]
* die Art von TextTrack, den Sie hinzufügen
*
* @param {string} [label]
* das Label, das dem TextTrack-Label gegeben werden soll
*
* @param {string} [Sprache]
* die Sprache, die auf dem TextTrack eingestellt werden soll
*
* @return {TextTrack|undefined}
* der TextTrack, der hinzugefügt oder undefiniert wurde
* wenn es keine Technologie gibt
* /
addTextTrack(kind, label, language) {
if (this.tech_) {
gib this.tech_.addTextTrack zurück (Art, Bezeichnung, Sprache);
}
}
/**
* Erstellen Sie ein Remote-Objekt {@link TextTrack} und ein {@link HtmlTrackElement}.
* Wenn ManualCleanup auf false gesetzt ist, wird der Track automatisch entfernt
* bei Quelländerungen.
*
* @param {Object} options
* Optionen, die während der Erstellung an {@link htmlTrackElement} übergeben werden. Sehen
* {@link HtmlTrackElement} für Objekteigenschaften, die Sie verwenden sollten.
*
* @param {boolean} [manualCleanup=true] wenn auf false gesetzt, wird der TextTrack
* bei einem Quellwechsel entfernt
*
* @return {htmlTrackElement}
* das HTMLTrackElement, das erstellt und hinzugefügt wurde
* zur HtmlTrackElementList und zur Fernbedienung
* Text-Trackliste
*
* @deprecated Der Standardwert des Parameters "manualCleanup" ist standardmäßig
* in zukünftigen Versionen von Video.js auf „falsch“
* /
addRemoteTextTrack(options, manualCleanup) {
if (this.tech_) {
gib this.tech_.addRemoteTextTrack zurück (Optionen, ManualCleanup);
}
}
/**
* Entferne eine Fernbedienung {@link TextTrack} aus dem jeweiligen
* {@link textTrackList} und {@link htmlTrackElementList}.
*
* @param {Object} verfolgen
* Remote {@link TextTrack} zum Entfernen
*
* @return {undefined}
* gibt nichts zurück
* /
removeRemoteTextTrack (obj = {}) {
lass {track} = obj;
if (!track) {
Titel = obj;
}
//destrukturiere die Eingabe in ein Objekt mit einem Track-Argument, standardmäßig mit Argumenten [0]
//Das gesamte Argument wird standardmäßig auf ein leeres Objekt gesetzt, wenn nichts übergeben wurde
if (this.tech_) {
gib this.tech_.removeRemoteTextTrack (track) zurück;
}
}
/**
* Ruft verfügbare Metriken zur Qualität der Medienwiedergabe ab, wie sie vom W3C's Media
* Wiedergabequalität API.
*
* @see [Spec]{@link https://wicg.github.io/media-playback-quality}
*
* @return {Object|undefined}
* Ein Objekt mit unterstützten Qualitätsmetriken für die Medienwiedergabe oder undefiniert, falls vorhanden
* ist keine Technologie oder die Technologie unterstützt sie nicht.
* /
getVideoPlaybackQuality() {
gib this.techGet_ ('getVideoPlaybackQuality') zurück;
}
/**
* Videobreite abrufen
*
* @return {number}
* aktuelle Videobreite
* /
VideoBreite () {
gib this.tech_ && this.tech_.videoWidth & this.tech_.videoWidth () || 0;
}
/**
* Videohöhe abrufen
*
* @return {number}
* aktuelle Videohöhe
* /
Videohöhe () {
gib this.tech_ && this.tech_.VideoHeight && this.tech_.videoHeight () || 0; zurück
}
/**
* Der Sprachcode des Spielers.
*
* Das Ändern der Sprache wird ausgelöst
* [Sprachwechsel] {@link Spieler #Event: Sprachwechsel}
* welche Komponenten zur Aktualisierung des Steuertextes verwendet werden können.
* ClickableComponent aktualisiert seinen Steuertext standardmäßig am
* [Sprachwechsel] {@link Spieler #Event: Sprachwechsel}.
*
* @fires Spieler #languagechange
*
* @param {Zeichenfolge} [Code]
* der Sprachcode, auf den der Player eingestellt werden soll
*
* @return {string}
* Der aktuelle Sprachcode beim Abrufen
* /
Sprache (Code) {
if (code === undefiniert) {
gib this.language_ zurück;
}
wenn (this.language_! == Zeichenfolge (Code) .toLowerCase ()) {
this.language_ = Zeichenfolge (Code) .toLowerCase ();
//beim ersten Init ist es möglich, dass einige Dinge nicht passieren
if (isEvented(this)) {
/**
* Wird ausgelöst, wenn sich die Spielersprache ändert
*
* @event Spieler #languagechange
* @Typ {EventTarget~Event}
* /
this.trigger ('Sprachwechsel');
}
}
}
/**
* Holen Sie sich das Sprachwörterbuch des Spielers
* Jedes Mal zusammenführen, da ein neu hinzugefügtes Plugin VideoJS.addLanguage () jederzeit aufrufen kann
* Die direkt in den Spieleroptionen angegebenen Sprachen haben Vorrang
*
* @return {Array}
* Eine Reihe unterstützter Sprachen
* /
Sprachen () {
gib mergeOptions zurück (player.prototype.options_.languages, this.languages_);
}
/**
* gibt ein JavaScript-Objekt zurück, das den aktuellen Track repräsentiert
* Informationen. **GIBT es nicht als JSON zurück**
*
* @return {Object}
* Objekt, das den aktuellen Stand der Track-Informationen darstellt
* /
zu JSON () {
const-Optionen = mergeOptions (this.options_);
const tracks = options.tracks;
options.tracks = [];
for (let i = 0; i < tracks.length; i++) {
lettrack = Spuren [i];
//Tracks tiefenzusammenführen und den Player auf Null setzen, also keine zirkulären Verweise
track = mergeOptions (track);
track.player = undefiniert;
options.tracks [i] = verfolgen;
}
Rückgabeoptionen;
}
/**
* Erzeugt einen einfachen modalen Dialog (eine Instanz von {@link modalDialog}
* Komponente), die den Spieler sofort mit beliebigen
* Inhalt und entfernt sich beim Schließen von selbst.
*
* @param {string|function|element|array|Null} Inhalt
* Entspricht dem gleichnamigen Parameter von {@link modalDialog #content}.
* Die einfachste Verwendung besteht darin, eine Zeichenfolge oder ein DOM bereitzustellen
* element.
*
* @param {Object} [Optionen]
* Zusätzliche Optionen, die an den {@link modalDialog} weitergegeben werden.
*
* @return {modalDialog}
* der {@link modalDialog}, der erstellt wurde
* /
createModal (Inhalt, Optionen) {
optionen = Optionen || {};
options.content = Inhalt || „;
const modal = new ModalDialog (dies, Optionen);
this.addChild (modal);
modal.on ('entsorgen', () => {
this.removeChild (modal);
});
modal.open ();
modales zurückgeben;
}
/**
* Ändere die Breakpoint-Klassen, wenn der Spieler die Größe ändert.
*
* @privat
* /
AktuellesBreakPoint_ () {
wenn (! diese.responsive ()) {
rückkehr;
}
const currentBreakpoint = this.currentBreakpoint ();
const currentWidth = this.currentWidth ();
für (sei i = 0; i < breakPoint_Order.length; i++) {
const candidateBreakpoint = BREAKPOINT_ORDER [i];
const maxWidth = this.breakpoints_ [candidateBreakpoint];
wenn (currentWidth <= maxWidth) {
//Der aktuelle Breakpoint hat sich nicht geändert, es gibt nichts zu tun.
wenn (currentBreakpoint === candidateBreakpoint) {
rückkehr;
}
//Entferne eine Klasse nur, wenn es einen aktuellen Breakpoint gibt.
wenn (currentBreakPoint) {
this.removeClass (BREAKPOINT_CLASSES [CurrentBreakpoint]);
}
this.addClass (BREAKPOINT_CLASSES [CandidateBreakpoint]);
this.breakpoint_ = CandidateBreakpoint;
pause;
}
}
}
/**
* Löscht den aktuellen Breakpoint.
*
* @privat
* /
Entferne den aktuellen Breakpoint _ () {
const Klassenname = this.currentBreakPointClass ();
this.breakpoint_ = '';
wenn (Klassenname) {
this.removeClass (Klassenname);
}
}
/**
* Erhalte Breakpoints oder setze sie für den Spieler.
*
* Der Aufruf dieser Methode mit einem Objekt oder `true` entfernt alle vorherigen
* benutzerdefinierte Breakpoints und beginnen Sie wieder mit den Standardeinstellungen.
*
* @param {object|Boolean} [Breakpoints]
* Wenn ein Objekt angegeben ist, kann es verwendet werden, um benutzerdefinierte bereitzustellen
* haltepunkte. Wenn `true` angegeben ist, werden Standard-Breakpoints gesetzt.
* Wenn dieses Argument nicht angegeben ist, wird einfach der aktuelle Wert zurückgegeben
* haltepunkte.
*
* @param {Zahl} [breakpoints.tiny]
* Die maximale Breite für die Klasse „vjs-layout-tiny“.
*
* @param {Zahl} [breakpoints.xsmall]
* Die maximale Breite für die Klasse „vjs-layout-x-small“.
*
* @param {Zahl} [breakpoints.small]
* Die maximale Breite für die Klasse „vjs-layout-small“.
*
* @param {Zahl} [breakpoints.medium]
* Die maximale Breite für die Klasse „vjs-layout-medium“.
*
* @param {Zahl} [breakpoints.large]
* Die maximale Breite für die Klasse „vjs-layout-large“.
*
* @param {Zahl} [breakpoints.xlarge]
* Die maximale Breite für die Klasse „vjs-layout-x-large“.
*
* @param {Zahl} [breakpoints.huge]
* Die maximale Breite für die Klasse „vjs-layout-huge“.
*
* @return {Object}
* Ein Objekt, das Breakpoint-Namen maximalen Breitenwerten zuordnet.
* /
Haltepunkte (Haltepunkte) {
// Wird als Getter verwendet.
if (Breakpoints === undefiniert) {
return assign(this.breakpoints_);
}
this.breakpoint_ = '';
this.breakpoints_ = assign ({}, DEFAULT_BREAKPOINTS, Breakpoints);
//Wenn sich die Breakpoint-Definitionen ändern, müssen wir die aktuelle Version aktualisieren
//ausgewählter Breakpoint.
this.updateCurrentBreakpoint_();
//Klonen Sie die Breakpoints, bevor Sie zurückkehren.
return assign(this.breakpoints_);
}
/**
* Erhalte oder setze eine Flagge, die angibt, ob sich dieser Spieler anpassen sollte oder nicht
* seine Benutzeroberfläche basiert auf seinen Abmessungen.
*
* @param {boolean} -Wert
* Sollte `true` sein, wenn der Spieler seine Benutzeroberfläche entsprechend anpassen soll
* Abmessungen; andernfalls sollte `falsch` sein.
*
* @return {boolean}
* Wird „wahr“ sein, wenn dieser Spieler seine Benutzeroberfläche an seine anpassen sollte
* Abmessungen; andernfalls ist es `falsch`.
* /
responsiv (Wert) {
// Wird als Getter verwendet.
if (Wert === undefiniert) {
gib this.responsive_ zurück;
}
Wert = Boolean (Wert);
const current = this.responsive_;
//Nichts hat sich geändert.
if (Wert === aktuell) {
rückkehr;
}
//Der Wert hat sich tatsächlich geändert, lege ihn fest.
this.responsive_ = Wert;
//Beginne, auf Breakpoints zu warten und setze den anfänglichen Breakpoint, wenn
//Der Player reagiert jetzt.
wenn (Wert) {
this.on ('playerresize', this.boundUpdateCurrentBreakPoint_);
this.updateCurrentBreakpoint_();
//Höre auf, nach Breakpoints zu suchen, wenn der Player nicht mehr reagiert.
} sonst {
this.off ('playerresize', this.boundUpdateCurrentBreakPoint_);
this.removeCurrentBreakPoint_ ();
}
rückgabewert;
}
/**
* Ruft den aktuellen Breakpoint-Namen ab, falls vorhanden.
*
* @return {string}
* Wenn aktuell ein Breakpoint gesetzt ist, gibt a den Schlüssel aus dem
* Breakpoint-Objekt, das dazu passt. Andernfalls wird eine leere Zeichenfolge zurückgegeben.
* /
aktueller Breakpoint () {
gib this.breakpoint_ zurück;
}
/**
* Ruft den aktuellen Breakpoint-Klassennamen ab.
*
* @return {string}
* Der passende Klassenname (z. B. `"vjs-layout-tiny"` oder
* `"vjs-layout-large"`) für den aktuellen Breakpoint. Leere Zeichenfolge wenn
* es gibt keinen aktuellen Breakpoint.
* /
CurrentBreakPointClass () {
return BREAKPOINT_CLASSES [this.breakpoint_] || „;
}
/**
* Ein Objekt, das ein einzelnes Medium beschreibt.
*
* Eigenschaften, die nicht Teil dieser Typbeschreibung sind, werden beibehalten; also
* Dies kann auch als generischer Mechanismus zur Speicherung von Metadaten angesehen werden.
*
* @see {@link https://wicg.github.io/mediasession/#the-mediametadata-interface}
* @typedef {Object} player~MediaObject
*
* @property {string} [album]
* Unbenutzt, außer wenn dieses Objekt an die `MediaSession` übergeben wird
* API.
*
* @property {string} [Künstler]
* Unbenutzt, außer wenn dieses Objekt an die `MediaSession` übergeben wird
* API.
*
* @property {Object []} [Kunstwerk]
* Unbenutzt, außer wenn dieses Objekt an die `MediaSession` übergeben wird
* API. Falls nicht angegeben, wird über das `Poster` aufgefüllt, wenn
* verfügbar.
*
* @property {string} [Plakat]
* URL zu einem Bild, das vor der Wiedergabe angezeigt wird.
*
* @property {tech~sourceobject|tech~sourceObject [] |string} [src]
* Ein einzelnes Quellobjekt, ein Array von Quellobjekten oder eine Zeichenfolge
* Verweis auf eine URL zu einer Medienquelle. Es wird _sehr empfehlenswert_
* dass hier ein Objekt oder ein Array von Objekten verwendet wird, also diese Quelle
* Auswahlalgorithmen können den `Typ` berücksichtigen.
*
* @property {string} [Titel]
* Unbenutzt, außer wenn dieses Objekt an die `MediaSession` übergeben wird
* API.
*
* @property {Objekt []} [TextTracks]
* Eine Reihe von Objekten, die zur Erstellung von Textspuren verwendet werden können, wie folgt
* das {@link https://www.w3.org/TR/html50/embedded-content-0.html#the-track-element|native Track-Element-Format}.
* Zur leichteren Entfernung werden diese als „Remote-Text“ erstellt
* verfolgt und ist so eingestellt, dass Änderungen an der Quelle automatisch bereinigt werden.
*
* Diese Objekte können Eigenschaften wie `src`, `kind`, `label` haben,
* und `Sprache`, siehe {@link Tech #createRemoteTextTrack}.
* /
/**
* Füllen Sie den Player mit einem {@link Player~MediaObject|MediaObject}.
*
* @param {player~mediaObject} Medien
* Ein Medienobjekt.
*
* @param {Function} bereit
* Ein Rückruf, der angerufen wird, wenn der Spieler bereit ist.
* /
loadMedia (media, bereit) {
wenn (! Medien | Art des Mediums! == 'Objekt') {
rückkehr;
}
this.reset ();
//Klone das Medienobjekt, damit es nicht von außen mutiert werden kann.
this.cache_.media = MergeOptions (Medien);
const {Kunstwerk, Poster, src, TextTracks} = this.cache_.media;
//Falls `Artwork` nicht angegeben ist, erstelle es mit `Poster`.
wenn (! Kunstwerk und Poster) {
this.cache_.media.artwork = [{
src: Plakat,
Typ: getMimeType (Poster)
}];
}
wenn (src) {
diese.src (src);
}
wenn (Poster) {
dieses.poster (Plakat);
}
wenn (Array.isArray (TextTracks)) {
textTracks.forEach (tt => this.addRemoteTextTrack (tt, falsch));
}
this.ready(ready);
}
/**
* Besorge dir einen Klon des aktuellen {@link player~mediaObject} für diesen Spieler.
*
* Wenn die `loadMedia`-Methode nicht verwendet wurde, wird versucht, eine zurückzugeben
* {@link player~mediaObject} basiert auf dem aktuellen Status des Spielers.
*
* @return {player~mediaObject}
* /
getMedia () {
wenn (! this.cache_.media) {
const poster = this.poster ();
const src = this.CurrentSources ();
const textTracks = array.prototype.Map.call (this.remoteTextTracks (), (tt) => ({
Art: tt.kind,
Etikett: tt.label,
sprache: tt.language,
src: tt.src
}));
const media = {src, textTracks};
wenn (Poster) {
media.poster = Plakat;
mediales Kunstwerk = [{
src: media.poster,
Typ: getMimeType (media.poster)
}];
}
Medien zurückgeben;
}
gib mergeOptions (this.cache_.media) zurück;
}
/**
* Ruft Tag-Einstellungen ab
*
* @param {Element} tag
* Das Spielerkennzeichen
*
* @return {Object}
* Ein Objekt, das alle Einstellungen enthält
* für ein Spieler-Tag
* /
statische getTagSettings (Tag) {
const baseOptions = {
quellen: [],
Titel: []
};
const tagOptions = dom.getAttributes (Tag);
const DataSetup = TagOptions ['Daten-Setup'];
wenn (dom.hasClass (tag, 'vjs-fill')) {
tagOptions.Fill = wahr;
}
wenn (dom.hasClass (tag, 'vjs-fluid')) {
tagOptions.Fluid = wahr;
}
// Prüfen, ob data-setup attr existiert.
wenn (DataSetup! == null) {
//Analysieren Sie die JSON-Optionen
//Wenn die Zeichenfolge leer ist, mache sie zu einem analysierbaren JSON-Objekt.
const [Fehler, Daten] = safeParseTuple (DataSetup || '{}');
if (err) {
log.error (Fehler);
}
assign (TagOptions, Daten);
}
zuweisen (BaseOptions, TagOptions);
//Holen Sie sich die Tag-Kindereinstellungen
wenn (tag.hasChildNodes ()) {
const children = tag.ChildNodes;
für (sei i = 0, j = kinder.length; i < j; i++) {
const child = Kinder [i];
//Groß- und Kleinschreibung ändern: http://ejohn.org/blog/nodename-case-sensitivity/
const childName = child.nodeName.toLowerCase ();
if (ChildName === 'Quelle') {
baseOptions.sources.push (dom.getAttributes (Kind));
} sonst wenn (childName === 'track') {
baseOptions.tracks.push (dom.getAttributes (Kind));
}
}
}
BaseOptions zurückgeben;
}
/**
* Stellen Sie fest, ob Flexbox unterstützt wird oder nicht
*
* @return {boolean}
* - wahr, wenn Flexbox unterstützt wird
* - falsch, wenn Flexbox nicht unterstützt wird
* /
Flex wird nicht unterstützt _ () {
const elem = document.createElement ('i');
//Hinweis: Wir verwenden FlexBasis (oder FlexOrder) nicht, aber es ist eines der mehr
//allgemeine Flex-Funktionen, auf die wir uns verlassen können, wenn wir nach Flex-Unterstützung suchen.
kehre zurück! ('FlexBasis' in elem.style) ||
'WebKitFlexBasis' in elem.style ||
'MozFlexBasis' in elem.style ||
'msFlexBasis' in elem.style ||
//IE10-spezifisch (Flex-Spezifikation 2012), der Vollständigkeit halber verfügbar
'msFlexOrder' in elem.style);
}
/**
* Stellen Sie den Debug-Modus ein, um Protokolle auf Infoebene zu aktivieren/deaktivieren.
*
* @param {boolean} aktiviert
* @fires Spieler #debugon
* @fires Spieler #debugoff
* /
debuggen (aktiviert) {
if (aktiviert === undefiniert) {
gib this.debugEnabled_ zurück;
}
wenn (aktiviert) {
this.trigger ('debugon');
this.previousLogLevel_ = diese.log.level;
this.log.level ('debuggen');
this.debugEnabled_ = wahr;
} sonst {
this.trigger ('Debugoff');
this.log.level (this.previousLogLevel_);
this.previousLogLevel_ = undefiniert;
this.debugEnabled_ = false;
}
}
/**
* Stellen Sie die aktuellen Wiedergabegeschwindigkeiten ein oder rufen Sie sie ab.
* Nimmt ein Array und aktualisiert das Menü mit den Wiedergaberaten mit den neuen Elementen.
* Geben Sie ein leeres Array ein, um das Menü auszublenden.
* Andere Werte als Arrays werden ignoriert.
*
* @fires Spieler #playbackrateschange
* @param {number []} Neue Preise
* Die neuen Raten, auf die das Menü mit den Wiedergaberaten aktualisiert werden sollte.
* Ein leeres Array wird das Menü verbergen
* @return {number []} Bei Verwendung als Getter werden die aktuellen Wiedergabegeschwindigkeiten zurückgegeben
* /
Wiedergaberaten (neue Raten) {
if (newRates === undefiniert) {
gib this.cache_.playbackRates zurück;
}
//ignoriere jeden Wert, der kein Array ist
wenn (! Array.isArray (neue Raten) {
rückkehr;
}
//ignoriere alle Arrays, die nicht nur Zahlen enthalten
wenn (! newrates.every ((rate) => Ratentyp === 'Zahl')) {
rückkehr;
}
this.cache_.playbackRates = Neue Raten;
/**
* wird ausgelöst, wenn die Wiedergabegeschwindigkeit in einem Player geändert wird
*
* @event Spieler #playbackrateschange
* @Typ {EventTarget~Event}
* /
this.trigger ('Die Wiedergabegeschwindigkeit ändert sich');
}
}
/**
* Abrufen der {@link VideoTrackList}
* @link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist
*
* @return {videoTrackList}
* die aktuelle Video-Trackliste
*
* @method player.prototype.VideoTracks
* /
/**
* Abrufen der {@link AudioTrackList}
* @link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist
*
* @return {AudioTrackList}
* die aktuelle Audio-Trackliste
*
* @method Player.prototype.AudioTracks
* /
/**
* Abrufen der {@link TextTrackList}
*
* @link http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks
*
* @return {TextTrackList}
* die aktuelle Text-Titelliste
*
* @method player.prototype.TextTracks
* /
/**
* Hol dir die Fernbedienung {@link textTrackList}
*
* @return {TextTrackList}
* Die aktuelle Remote-Text-Titelliste
*
* @method player.prototype.remoteTextTracks
* /
/**
* Holen Sie sich die Remote-Tracks von {@link htmlTrackElementList}.
*
* @return {htmlTrackElementList}
* Die aktuelle Liste der Remote-Texttrack-Elemente
*
* @method player.prototype.remoteTextTrackels
* /
track_types.names.forEach (Funktion (Name) {
const props = TRACK_TYPES[name];
player.prototype [props.getterName] = Funktion () {
if (this.tech_) {
gib this.tech_ [props.getterName] () zurück;
}
//falls wir LoadTech_ noch nicht haben, erstellen wir {Video, Audio, Text} Tracks_
//diese werden beim Laden an den Techniker weitergegeben
this[props.privateName] = this[props.privateName] || new props.ListClass();
return this[props.privateName];
};
});
/**
* Ruft die Crossorigin-Option des `Player` ab oder legt sie fest. Für den HTML5-Player bedeutet dies
* setzt die Eigenschaft "crossOrigin" auf den Tag "<video>", um den CORS zu steuern
* verhalten.
*
* @see [Video Element Attributes]{@link https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#attr-crossorigin}
*
* @param {string} [Wert]
* Der Wert, auf den der Crossorigin des `Player` gesetzt werden soll. Wenn ein Argument
* angegeben wird, muss eine der Optionen "anonymous" oder "use-credentials" sein.
*
* @return {string|undefined}
* - Der aktuelle Crossorigin-Wert des `Player` beim Abrufen.
* - undefiniert bei der Einstellung
* /
player.prototype.crossOrigin = player.prototype.CrossOrigin;
/**
* Weltweite Aufzählung der Spieler.
*
* Die Schlüssel sind die Spieler-IDs und die Werte sind entweder der {@link Player}
* Instanz oder `Null` für entlassene Spieler.
*
* @Typ {Objekt}
* /
Spieler.Spieler = {};
const navigator = Fensternavigator;
/*
* Optionen für Spielerinstanzen, die mithilfe von Optionen angezeigt wurden
* Optionen = Player.prototype.options_
* Nehmen Sie Änderungen an den Optionen vor, nicht hier.
*
* @Typ {Objekt}
* @privat
* /
player.prototype.options_ = {
//Standardreihenfolge der Fallback-Technologie
Technischer Auftrag: tech.defaultTechOrder_,
html5: {},
//Standard-Inaktivitäts-Timeout
Inaktivitäts-Timeout: 2000,
//Standard-Wiedergabegeschwindigkeiten
playbackRates: [],
//Füge die Auswahl der Wiedergabegeschwindigkeit hinzu, indem du Raten hinzufü
//'Wiedergaberaten': [0,5, 1, 1,5, 2],
liveui: falsch,
//Mitgelieferte Steuersets
kinder: [
'MediaLoader',
'Hinteres Bild',
'TextTrackDisplay',
'Spinner laden',
'Große Play-Taste',
'LiveTracker',
'Steuerleiste',
'Fehleranzeige',
'TextTrack-Einstellungen',
'Größenverwalter'
],
language: navigator && (navigator.languages && navigator.languages [0] || navigator.userLanguage || navigator.language) || 'de',
//Gebietsschemas und ihre Sprachübersetzungen
Sprachen: {},
//Standardnachricht, die angezeigt wird, wenn ein Video nicht abgespielt werden kann.
Meldung wird nicht unterstützt: 'Für dieses Medium wurde keine kompatible Quelle gefunden. ',
normalizeAutoplay: falsch,
Vollbild: {
Optionen: {
navigationUI: 'verstecken'
}
},
Haltepunkte: {},
responsiv: falsch,
AudioOnlyMode: falsch,
audioPosterMode: falsch
};
[
/**
* Gibt zurück, ob sich der Spieler im Status „beendet“ befindet oder nicht.
*
* @return {Boolean} Wahr, wenn sich der Spieler im Zustand „Beendet“ befindet, andernfalls falsch.
* @method Spieler #ended
* /
beendet",
/**
* Gibt zurück, ob sich der Spieler im Status „Sucht“ befindet oder nicht.
*
* @return {Boolean} Wahr, wenn sich der Spieler im Suchzustand befindet, falsch, wenn nicht.
* @method Spieler #seeking
* /
suchen",
/**
* Gibt die TimeRange der aktuell verfügbaren Medien zurück
* um danach zu suchen.
*
* @return {timeRanges} die durchsuchbaren Intervalle der Medien-Timeline
* @method Spieler #seekable
* /
suchbar',
/**
* Gibt den aktuellen Status der Netzwerkaktivität für das Element zurück, von
* die Codes in der folgenden Liste.
* - NETWORK_EMPTY (numerischer Wert 0)
* Das Element wurde noch nicht initialisiert. Alle Attribute sind in
* ihre Anfangszustände.
* - NETWORK_IDLE (numerischer Wert 1)
* Der Algorithmus zur Ressourcenauswahl des Elements ist aktiv und hat
* hat eine Ressource ausgewählt, aber sie verwendet das Netzwerk nicht wirklich unter
* dieses Mal.
* - NETWORK_LOADING (numerischer Wert 2)
* Der Benutzeragent versucht aktiv, Daten herunterzuladen.
* - NETWORK_NO_SOURCE (numerischer Wert 3)
* Der Algorithmus zur Ressourcenauswahl des Elements ist aktiv, hat aber
* noch keine Ressource zur Verwendung gefunden.
*
* @see https://html.spec.whatwg.org/multipage/embedded-content.html#network-states
* @return {number} der aktuelle Status der Netzwerkaktivität
* @method Spieler #networkState
* /
netzwerk-Status",
/**
* Gibt einen Wert zurück, der den aktuellen Zustand des Elements ausdrückt
* in Bezug auf das Rendern der aktuellen Wiedergabeposition aus dem
* Codes in der folgenden Liste.
* - HAVE_NOTHING (numerischer Wert 0)
* Es sind keine Informationen zur Medienressource verfügbar.
* - HAVE_METADATA (numerischer Wert 1)
* Von der Ressource wurde so viel beschafft, dass die Dauer des
* Ressource ist verfügbar.
* - HAVE_CURRENT_DATA (numerischer Wert 2)
* Daten für die unmittelbar aktuelle Wiedergabeposition sind verfügbar.
* - HAVE_FUTURE_DATA (numerischer Wert 3)
* Daten für die unmittelbar aktuelle Wiedergabeposition sind verfügbar, als
* sowie genügend Daten für den Benutzeragenten, um den aktuellen
* Wiedergabeposition in Richtung der Wiedergabe.
* - HAVE_ENOUGH_DATA (numerischer Wert 4)
* Der Benutzeragent schätzt, dass genügend Daten verfügbar sind für
* Wiedergabe, um ununterbrochen fortzufahren.
*
* @see https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-readystate
* @return {number} der aktuelle Renderstatus der Wiedergabe
* @method Spieler #readyState
* /
'Bereitschaft'
] .forEach (Funktion (fn) {
player.prototype [fn] = Funktion () {
gib this.techGet_ (fn) zurück;
};
});
tech_events_retrigger.forEach (Funktion (Ereignis) {
player.prototype [`handleTech$ {toTitleCase (event)} _`] = function () {
gib this.trigger (event) zurück;
};
});
/**
* Wird abgefeuert, wenn der Spieler die anfänglichen Dauer- und Dimensionsinformationen hat
*
* @Ereignis Player#geladenMetadaten
* @Typ {EventTarget~Event}
* /
/**
* Wird ausgelöst, wenn der Player Daten an der aktuellen Wiedergabeposition heruntergeladen hat
*
* @event Player#loadeddata
* @Typ {EventTarget~Event}
* /
/**
* Wird ausgelöst, wenn sich die aktuelle Wiedergabeposition geändert hat *
* Während der Wiedergabe wird dieser alle 15-250 Millisekunden ausgelöst, abhängig von
* Verwendetechnologie.
*
* @event Player#timeupdate
* @Typ {EventTarget~Event}
* /
/**
* Wird ausgelöst, wenn sich die Lautstärke ändert
*
* @event Player#Lautstärkeänderung
* @Typ {EventTarget~Event}
* /
/**
* Meldet, ob für einen Player ein Plugin verfügbar ist oder nicht.
*
* Es wird nicht gemeldet, ob das Plugin jemals initialisiert wurde oder nicht
* auf diesem Spieler. Dafür [UsingPlugin] {@link Player #usingPlugin}.
*
* @method Spieler #hasPlugin
* @param {string} name
* Der Name eines Plugins.
*
* @return {boolean}
* Ob für diesen Player das angeforderte Plugin verfügbar ist oder nicht.
* /
/**
* Meldet namentlich, ob ein Spieler ein Plugin verwendet oder nicht.
*
* Bei Basis-Plugins wird nur gemeldet, ob das Plugin _immer_
* auf diesem Player initialisiert.
*
* @method Spieler #usingPlugin
* @param {string} name
* Der Name eines Plugins.
*
* @return {boolean}
* Ob dieser Player das angeforderte Plugin verwendet oder nicht.
* /
component.registerComponent ('Spieler', Spieler);
Standard-Player exportieren;