/**
* @file modal-dialog.js
* /
import * as Dom from './utils/dom';
importiere Komponente von './komponente';
import window from 'global/window';
dokument aus 'global/document' importieren;
import keycode from 'keycode';
const MODAL_CLASS_NAME = 'vjs-modal-dialog';
/**
* Der `ModalDialog` wird über dem Video und seinen Steuerelementen angezeigt, der blockiert
* Interaktion mit dem Spieler, bis er geschlossen wird.
*
* Modale Dialoge enthalten eine Schaltfläche „Schließen“ und werden geschlossen, wenn diese Schaltfläche
* ist aktiviert - oder wenn ESC an einer beliebigen Stelle gedrückt wird.
*
* @erweitert Komponente
* /
Klasse ModalDialog erweitert Komponente {
/**
* Erstellen Sie eine Instanz dieser Klasse.
*
* @param {Player} Spieler
* Der `Player`, dem diese Klasse zugeordnet werden soll.
*
* @param {Object} [Optionen]
* Der Schlüssel/Wertspeicher der Playeroptionen.
*
* @param {Gemischt} [options.content=undefiniert]
* Stellen Sie benutzerdefinierte Inhalte für dieses Modal bereit.
*
* @param {string} [Optionen.beschreibung]
* Eine Textbeschreibung für das Modal, hauptsächlich aus Gründen der Barrierefreiheit.
*
* @param {boolean} [options.FillAlways=Falsch]
* Normalerweise werden Modals nur beim ersten Mal automatisch gefüllt
* sie öffnen. Dadurch wird das Modal angewiesen, seinen Inhalt zu aktualisieren
* jedes Mal, wenn es geöffnet wird.
*
* @param {string} [options.label]
* Eine Textbezeichnung für das Modal, hauptsächlich aus Gründen der Barrierefreiheit.
*
* @param {boolean} [options.pauseOnOpen=wahr]
* Wenn `true` ist, wird die Wiedergabe angehalten, wenn
* Das Modal wird geöffnet und beim Schließen wieder aufgenommen.
*
* @param {boolean} [options.temporary=wahr]
* Wenn `true`, kann das Modal nur einmal geöffnet werden; es wird
* wird entsorgt, sobald es geschlossen ist.
*
* @param {boolean} [options.uncloseable=falsch]
* Wenn `true` ist, kann der Benutzer das Modal nicht schließen
* über die Benutzeroberfläche auf die normale Weise. Programmatisches Schließen ist
* immer noch möglich.
* /
constructor(spieler, optionen) {
super(Spieler, Optionen);
this.handleKeyDown_ = (e) => this.handleKeyDown(e);
this.close_ = (e) => this.close (e);
this.opened_ = this.hasBeenOpened_ = this.hasBeenFilled_ = falsch;
this.closeable (! this.options_.uncloseable);
this.content (this.options_.content);
//Stellen Sie sicher, dass der ContentEl definiert ist, NACHDEM alle Kinder initialisiert wurden
//weil wir nur den Inhalt des Modals im ContentEl haben wollen
//(nicht die UI-Elemente wie die Schaltfläche zum Schließen).
this.contentEl_ = Dom.createEl('div', {
Klassenname: `$ {MODAL_CLASS_NAME} -content`
}, {
Rolle: 'Dokument'
});
this.descel_ = dom.createEl ('p', {
Klassenname: `$ {MODAL_CLASS_NAME} -description vjs-control-text`,
id: this.el () .getAttribute ('aria-describedby')
});
dom.textContent (this.descel_, this.description ());
this.el_.appendChild (this.descel_);
this.el_.appendChild (this.contentEL_);
}
/**
* Erstelle das DOM-Element des `ModalDialog`
*
* @return {Element}
* Das DOM-Element, das erstellt wird.
* /
createEl() {
return super.createEl('div', {
className: this.buildCSSClass(),
tabIndex: -1
}, {
'aria-describedby': `$ {this.id ()} _description`,
'aria-hidden': 'wahr',
'aria-label': this.label (),
'Rolle': 'Dialog'
});
}
dispose() {
this.contentEl_ = null;
this.descel_ = null;
this.previouslyActiveEl_ = null;
super.dispose();
}
/**
* Erzeugt den Standard-DOM "Klassenname".
*
* @return {string}
* Der DOM `className` für dieses Objekt.
* /
buildCSSClass() {
gib `$ {MODAL_CLASS_NAME} vjs-hidden $ {super.buildCssClass ()} `zurück;
}
/**
* Gibt die Label-Zeichenfolge für dieses Modal zurück. Wird hauptsächlich für die Barrierefreiheit verwendet.
*
* @return {string}
* die lokalisierte oder unformatierte Bezeichnung dieses Modals.
* /
label() {
gib this.localize (this.options_.label || 'Modales Fenster') zurück;
}
/**
* Gibt die Beschreibungszeichenfolge für dieses Modal zurück. Hauptsächlich verwendet für
* Barrierefreiheit.
*
* @return {string}
* Die lokalisierte oder rohe Beschreibung dieses Modals.
* /
description() {
let desc = this.options_.description || this.localize ('Dies ist ein modales Fenster');
//Hängt eine universelle Schließbarkeitsnachricht an, wenn das Modal schließbar ist.
wenn (this.closeable ()) {
desc += '' + this.localize ('Dieses Modal kann geschlossen werden, indem Sie die Esc-Taste drücken oder die Schaltfläche zum Schließen aktivieren. ');
}
Rückfahrt zum Abstieg;
}
/**
* Öffnet das Modal.
*
* @fires modalDialog #beforemodalopen
* @fires modalDialog #modalopen
* /
öffnen () {
if (!this.opened_) {
const player = this.player();
/**
* Wird ausgelöst, kurz bevor ein `ModalDialog` geöffnet wird.
*
* @event modalDialog #beforemodalopen
* @Typ {EventTarget~Event}
* /
this.trigger ('beforemodalopen');
this.opened_ = wahr;
//Inhalt füllen, wenn das Modal noch nie geöffnet wurde und
//wurde nie gefüllt.
if (this.options_.fillAlways ||! dies. wurde geöffnet _ &&! this.hasbeenFilled_) {
this.fill();
}
//Wenn der Spieler gespielt hat, pausiere es und notiere dir, wie es zuvor war
//Spielstatus.
this.wasPlaying_ =! player.pausiert ();
wenn (this.options_.pauseOnOpen && this.wasPlaying_) {
spieler.pause ();
}
this.on('keydown', this.handleKeyDown_);
//Steuerelemente ausblenden und notieren, ob sie aktiviert waren.
this.hadControls_= player.controls ();
player.controls (falsch);
this.show();
this.ConditionalFocus_ ();
this.el () .setAttribute ('aria-hidden', 'falsch');
/**
* Wird unmittelbar nach dem Öffnen eines `ModalDialog` ausgelöst.
*
* @event modalDialog #modalopen
* @Typ {EventTarget~Event}
* /
this.trigger ('modalopen');
this.hasBeenOpened_ = wahr;
}
}
/**
* Ob der `ModalDialog` gerade geöffnet oder geschlossen ist.
*
* @param {boolean} [Wert]
* Falls angegeben, wird das Modal geöffnet (`true`) oder geschlossen (`false`).
*
* @return {boolean}
* der aktuelle Öffnungsstatus des Modaldialogs
* /
geöffnet (Wert) {
if (typeof value === 'boolean') {
dieser [Wert? 'öffnen': 'schließen'] ();
}
gib this.opened_ zurück;
}
/**
* Schließt das Modal, tut nichts, wenn der `ModalDialog`
* nicht geöffnet.
*
* @fires modalDialog #beforemodalclose
* @fires modalDialog #modalclose
* /
schließen () {
if (!this.opened_) {
rückkehr;
}
const player = this.player();
/**
* Wird ausgelöst, kurz bevor ein `ModalDialog` geschlossen wird.
*
* @event modalDialog #beforemodalclose
* @Typ {EventTarget~Event}
* /
this.trigger ('beforemodalclose');
this.opened_ = falsch;
wenn (this.wasPlaying_ && this.options_.pauseOnOpen) {
spieler.play ();
}
this.off('keydown', this.handleKeyDown_);
wenn (this.hadControls_) {
player.controls (wahr);
}
this.hide();
this.el () .setAttribute ('aria-hidden', 'wahr');
/**
* Wird unmittelbar nach dem Schließen eines `ModalDialog` ausgelöst.
*
* @event modalDialog #modalclose
* @Typ {EventTarget~Event}
* /
this.trigger ('modalclose');
this.conditionalBlur_ ();
wenn (this.options_.temporary) {
this.dispose ();
}
}
/**
* Prüfen Sie, ob der `ModalDialog` über die Benutzeroberfläche geschlossen werden kann.
*
* @param {boolean} [Wert]
* Wenn es als boolescher Wert angegeben wird, wird die Option `closeable` gesetzt.
*
* @return {boolean}
* Gibt den Endwert der schließbaren Option zurück.
* /
schließbar (Wert) {
if (typeof value === 'boolean') {
const closeable = this.closeable_ =!! wert;
let close = this.getChild ('closeButton');
//Wenn dies schließbar gemacht wird und es keine Schaltfläche zum Schließen gibt, füge eine hinzu.
if (schließbar &&! schließen) {
//Der Schließen-Button sollte ein untergeordnetes Element des Modals sein - nicht sein
//Inhaltselement, also ändere das Inhaltselement vorübergehend.
const temp = this.contentEL_;
this.contentEL_ = this.el_;
close = this.addChild ('closeButton', {controlText: 'Modalen Dialog schließen'});
this.contentEL_ = temporärer Inhalt;
this.on (close, 'close', this.close_);
}
//Wenn dies nicht mehr geschlossen werden kann und über eine Schaltfläche zum Schließen verfügt, entfernen Sie es.
wenn (! schließbar & schließen) {
this.off (close, 'close', this.close_);
this.removeChild (schließen);
schließen.entsorgen ();
}
}
gib this.closeable_ zurück;
}
/**
* Füllen Sie das Inhaltselement des Modals mit der Option „Inhalt“ des Modals.
* Das Inhaltselement wird geleert, bevor diese Änderung stattfindet.
* /
füllen () {
this.fillWith (this.content ());
}
/**
* Füllen Sie das Inhaltselement des Modals mit beliebigem Inhalt.
* Das Inhaltselement wird geleert, bevor diese Änderung stattfindet.
*
* @fires modalDialog #beforemodalfill
* @fires modalDialog #modalfill
*
* @param {Gemischt} [Inhalt]
* Hier gelten die gleichen Regeln wie für die Option `Content`.
* /
fillWith (Inhalt) {
const contentEL = this.ContentEl ();
const parentEl = contentEL.parentNode;
const nextSibLingel = contentEL.NextSibling;
/**
* Wird ausgelöst, kurz bevor ein `ModalDialog` mit Inhalt gefüllt wird.
*
* @event modalDialog #beforemodalfill
* @Typ {EventTarget~Event}
* /
this.trigger ('beforemodalfill');
this.hasBeenFilled_ = wahr;
//Trenne das Inhaltselement vom DOM, bevor du es ausführst
//Manipulation, um zu vermeiden, dass das Live-DOM mehrfach geändert wird.
Parentel.removeChild (ContentEl);
diese.empty ();
dom.insertContent (ContentEl, Inhalt);
/**
* Wird ausgelöst, kurz nachdem ein `ModalDialog` mit Inhalt gefüllt wurde.
*
* @event modalDialog #modalfill
* @Typ {EventTarget~Event}
* /
this.trigger ('modalfill');
//Fügen Sie das neu gefüllte Inhaltselement erneut ein.
wenn (nächstes Geschwisterchen) {
Parentel.insertBefore (ContentEl, nextSiblingel);
} sonst {
Parentel.appendChild (ContentEl);
}
//stelle sicher, dass der Schließen-Button im Dialog DOM an letzter Stelle steht
const closeButton = this.getChild ('closeButton');
wenn (CloseButton) {
Parentel.appendChild (CloseButton.el_);
}
}
/**
* Leert das Inhaltselement. Dies geschieht jedes Mal, wenn das Modal gefüllt ist.
*
* @fires modalDialog #beforemodalempty
* @fires modalDialog #modalempty
* /
leer () {
/**
* Wird ausgelöst, kurz bevor ein `ModalDialog` geleert wird.
*
* @event modalDialog #beforemodalempty
* @Typ {EventTarget~Event}
* /
this.trigger ('beforemodalempty');
dom.emptyEl (this.ContentEl ());
/**
* Wird ausgelöst, kurz nachdem ein `ModalDialog` geleert wurde.
*
* @event modalDialog #modalempty
* @Typ {EventTarget~Event}
* /
this.trigger ('modalempty');
}
/**
* Ruft den modalen Inhalt ab oder legt ihn fest, der normalisiert wird, bevor er
* ins DOM gerendert.
*
* Dies aktualisiert das DOM nicht und füllt das Modal nicht, sondern es wird während des
* dieser Prozess.
*
* @param {Gemischt} [Wert]
* Legt, falls definiert, den internen Inhaltswert fest, der auf der
* nächste Aufrufe von `fill`. Dieser Wert wird normalisiert, bevor er
* eingefügt. Um den internen Inhaltswert zu „löschen“, übergeben Sie `null`.
*
* @return {Mixed}
* Der aktuelle Inhalt des modalen Dialogs
* /
Inhalt (Wert) {
if (typeof wert !== 'undefined') {
this.content_ = Wert;
}
gib this.content_ zurück;
}
/**
* Fokussiere den modalen Dialog bedingt, wenn der Fokus zuvor auf dem Spieler lag.
*
* @privat
* /
Bedingter Fokus_ () {
const activeEL = document.activeElement;
const playerEl = this.player_.el_;
this.previouslyActiveEl_ = null;
if (playerEL.contains (activeEL) || playerEL === activeEL) {
this.previouslyActiveL_ = ActiveL;
this.focus ();
}
}
/**
* das Element bedingt verwischen und das letzte fokussierte Element neu fokussieren
*
* @privat
* /
conditionalBlur_() {
wenn (this.previouslyActiveL_) {
this.previous activeel_.focus ();
this.previouslyActiveEl_ = null;
}
}
/**
* Keydown-Handler. Angehängt, wenn Modal fokussiert ist.
*
* @listens keydown
* /
handleKeyDown(event) {
//Erlaube nicht, dass Tastenkombinationen den modalen Dialog erreichen.
event.stopPropagation();
if (keyCode.isEventKey (event, 'Escape') && this.closeable ()) {
event.preventDefault();
this.close();
rückkehr;
}
//vorzeitig beenden, wenn es sich nicht um eine Tabulatortaste handelt
if (!keycode.isEventKey(event, 'Tab')) {
rückkehr;
}
const focusableEls = this.focusableEls_ ();
const activeEL = this.el_.QuerySelector (':focus');
lass focusIndex;
für (sei i = 0; i < focusableEls.length; i++) {
wenn (activeEL === focusableELs [i]) {
FokusIndex = i;
pause;
}
}
wenn (document.activeElement === this.el_) {
Fokusindex = 0;
}
wenn (event.shiftKey && focusIndex === 0) {
focusableELS [focusableELS.length - 1] .focus ();
event.preventDefault();
} sonst wenn (! event.shiftKey && focusIndex === FocusableEls.length - 1) {
focusableELS [0] .focus ();
event.preventDefault();
}
}
/**
* hol dir alle fokussierbaren Elemente
*
* @privat
* /
FocusableELS_ () {
const allChildren = this.el_.querySelectorAll ('*');
return Array.prototype.filter.call (allChildren, (child) => {
return ((untergeordnete Instanz von window.htmLanchorelement ||
untergeordnete Instanz von window.htmlAreaElement) & child.hasAttribute ('href')) ||
((untergeordnete Instanz von window.htmlinputElement ||
untergeordnete Instanz von window.htmlSelectElement ||
untergeordnete Instanz von window.htmlTextAreaElement ||
untergeordnete Instanz von window.htmlButtonElement) &&! child.hasAttribute ('deaktiviert') |
(untergeordnete Instanz von window.htmliFrameElement) ||
untergeordnete Instanz von window.htmlobjectElement ||
untergeordnete Instanz von window.htmlembedElement) ||
(child.hasAttribute ('tabindex') & child.getAttribute ('tabindex')! = -1) |
(child.hasAttribute ('contenteditable'));
});
}
}
/**
* Standardoptionen für die Standardoptionen von `ModalDialog`.
*
* @Typ {Objekt}
* @privat
* /
modalDialog.prototype.options_ = {
pauseOnOpen: wahr,
temporär: wahr
};
component.registerComponent ('modalDialog', modalDialog);
exportiert den Standard-ModalDialog;