/**
* @file text-track-settings.js
*/
import window from 'global/window' ;
import Component from '../component' ;
import ModalDialog from '../modal-dialog' ;
import {createEl} from '../utils/dom' ;
import * as Obj from '../utils/obj' ;
import log from '../utils/log' ;
const LOCAL_STORAGE_KEY = 'vjs-text-track-settings' ;
const COLOR_BLACK = ['#000', 'Black'] ;
const COLOR_BLUE = ['#00F', 'Blue'] ;
const COLOR_CYAN = ['#0FF', 'Cyan'] ;
const COLOR_GREEN = ['#0F0', 'Green'] ;
const COLOR_MAGENTA = ['#F0F', 'Magenta'] ;
const COLOR_RED = ['#F00', 'Red'] ;
const COLOR_WHITE = ['#FFF', 'White'] ;
const COLOR_YELLOW = ['#FF0', 'Yellow'] ;
const OPACITY_OPAQUE = ['1', 'Opaque'] ;
const OPACITY_SEMI = ['0.5', 'Semi-Transparent'] ;
const OPACITY_TRANS = ['0', 'Transparent'] ;
// Configuration des différents éléments <select> dans le DOM de ce composant.
//
// Les clés possibles sont les suivantes :
//
// `default` :
// L'indice de l'option par défaut. Ne doit être fourni que s'il n'est pas nul.
// `parser` :
// Une fonction qui est utilisée pour analyser la valeur de l'option sélectionnée en
// une manière personnalisée.
// `selector` :
// Le sélecteur utilisé pour trouver l'élément <select> associé.
const selectConfigs = {
backgroundColor : {
selector : '.vjs-bg-color > select',
id : 'captions-background-color-%s',
étiquette : couleur",
options : [
COLOR_BLACK,
COLOR_WHITE,
COLOR_RED,
COLOR_GREEN,
COLOR_BLUE,
COLOR_YELLOW,
COLOR_MAGENTA,
COLOR_CYAN
]
},
backgroundOpacity : {
selector : '.vjs-bg-opacity > select',
id : "captions-background-opacity-%s",
étiquette : transparence",
options : [
OPACITY_OPAQUE,
OPACITY_SEMI,
OPACITY_TRANS
]
},
color : {
selector : '.vjs-fg-color > select',
id : 'captions-foreground-color-%s',
étiquette : couleur",
options : [
COLOR_WHITE,
COLOR_BLACK,
COLOR_RED,
COLOR_GREEN,
COLOR_BLUE,
COLOR_YELLOW,
COLOR_MAGENTA,
COLOR_CYAN
]
},
edgeStyle : {
selector : '.vjs-edge-style > select',
id : '%s',
étiquette : style de bord de texte",
options : [
['none', 'None'],
["élevé", "élevé"],
["depressed", "Depressed"],
['uniforme', 'Uniforme'],
['dropshadow', 'Dropshadow']
]
},
fontFamily : {
selector : '.vjs-font-family > select',
id : 'captions-font-family-%s',
étiquette : famille de polices",
options : [
["proportionalSansSerif", "Proportional Sans-Serif"],
['monospaceSansSerif', 'Monospace Sans-Serif'],
["proportionalSerif", "Proportional Serif"],
['monospaceSerif', 'Monospace Serif'],
['casual', 'Casual'],
['script', 'Script'],
['small-caps', 'Small Caps']
]
},
fontPercent : {
selector : '.vjs-font-percent > select',
id : 'captions-font-size-%s',
étiquette : taille de la police",
options : [
['0.50', '50%'],
['0.75', '75%'],
['1.00', '100%'],
['1.25', '125%'],
['1.50', '150%'],
['1.75', '175%'],
['2.00', '200%'],
['3.00', '300%'],
['4.00', '400%']
],
par défaut : 2,
parser : (v) => v === '1.00' ? null : Nombre(v)
},
textOpacity : {
selector : '.vjs-text-opacity > select',
id : "captions-foreground-opacity-%s",
étiquette : transparence",
options : [
OPACITY_OPAQUE,
OPACITY_SEMI
]
},
// Les options de cet objet sont définies ci-dessous.
windowColor : {
selector : '.vjs-window-color > select',
id : 'captions-window-color-%s',
étiquette : couleur
},
// Les options de cet objet sont définies ci-dessous.
windowOpacity : {
selector : '.vjs-window-opacity > select',
id : 'captions-window-opacity-%s',
étiquette : transparence",
options : [
OPACITY_TRANS,
OPACITY_SEMI,
OPACITY_OPAQUE
]
}
};
selectConfigs.windowColor.options = selectConfigs.backgroundColor.options ;
/**
* Obtenir la valeur réelle d'une option.
*
* @param {string} value
* La valeur à obtenir
*
* @param {Fonction} [parser]
* Fonction optionnelle pour ajuster la valeur.
*
* @return {Mixed}
* - Sera `indéfini` si aucune valeur n'existe
* - Sera `undefined` si la valeur donnée est "none".
* - Dans le cas contraire, il s'agit de la valeur réelle.
*
* @private
*/
function parseOptionValue(value, parser) {
if (parser) {
valeur = parser(valeur) ;
}
if (value && value !== 'none') {
valeur de retour ;
}
}
/**
* Obtient la valeur de l'élément <option> sélectionné dans un élément <select> .
*
* @param {Element} el
* l'élément à rechercher
*
* @param {Fonction} [parser]
* Fonction optionnelle pour ajuster la valeur.
*
* @return {Mixed}
* - Sera `indéfini` si aucune valeur n'existe
* - Sera `undefined` si la valeur donnée est "none".
* - Dans le cas contraire, il s'agit de la valeur réelle.
*
* @private
*/
function getSelectedOptionValue(el, parser) {
const value = el.options[el.options.selectedIndex].value ;
return parseOptionValue(value, parser) ;
}
/**
* Définit l'élément <option> sélectionné dans un élément <select> sur la base d'un élément
* valeur donnée.
*
* @param {Element} el
* L'élément à examiner.
*
* @param {string} value
* la propriété à regarder.
*
* @param {Fonction} [parser]
* Fonction optionnelle permettant d'ajuster la valeur avant la comparaison.
*
* @private
*/
function setSelectedOption(el, value, parser) {
if (!value) {
retour ;
}
for (let i = 0 ; i < el.options.length ; i++) {
if (parseOptionValue(el.options[i].value, parser) === value) {
el.selectedIndex = i ;
pause ;
}
}
}
/**
* Manipuler les paramètres des pistes de texte.
*
* @extends ModalDialog
*/
class TextTrackSettings extends ModalDialog {
/**
* Crée une instance de cette classe.
*
* @param {Player} player
* Le `Player` auquel cette classe doit être attachée.
*
* @param {Objet} [options]
* La mémoire clé/valeur des options du lecteur.
*/
constructor(player, options) {
options.temporary = false ;
super(player, options) ;
this.updateDisplay = this.updateDisplay.bind(this) ;
// remplir la fenêtre modale et faire semblant de l'avoir ouverte
this.fill() ;
this.hasBeenOpened_ = this.hasBeenFilled_ = true ;
this.endDialog = createEl('p', {
className : 'vjs-control-text',
textContent : this.localize('Fin de la fenêtre de dialogue.')
}) ;
this.el().appendChild(this.endDialog) ;
this.setDefaults() ;
// Récupère `persistTextTrackSettings` des options du lecteur s'il n'est pas passé dans les options de l'enfant
if (options.persistTextTrackSettings === undefined) {
this.options_.persistTextTrackSettings = this.options_.playerOptions.persistTextTrackSettings ;
}
this.on(this.$('.vjs-done-button'), 'click', () => {
this.saveSettings() ;
this.close() ;
}) ;
this.on(this.$('.vjs-default-button'), 'click', () => {
this.setDefaults() ;
this.updateDisplay() ;
}) ;
Obj.each(selectConfigs, config => {
this.on(this.$(config.selector), 'change', this.updateDisplay) ;
}) ;
if (this.options_.persistTextTrackSettings) {
this.restoreSettings() ;
}
}
dispose() {
this.endDialog = null ;
super.dispose() ;
}
/**
* Créer un élément <select> avec des options configurées.
*
* @param {string} key
* Clé de configuration à utiliser lors de la création.
*
* @return {string}
* Une chaîne HTML.
*
* @private
*/
createElSelect_(key, legendId = '', type = 'label') {
const config = selectConfigs[key] ;
const id = config.id.replace('%s', this.id_) ;
const selectLabelledbyIds = [legendId, id].join(' ').trim() ;
retour [
`<${type} id="${id}" class="${type === 'label' ? 'vjs-label' : ''}">`,
this.localize(config.label),
`</${type}>`,
`<select aria-labelledby="${selectLabelledbyIds}">`
].
concat(config.options.map(o => {
const optionId = id + '-' + o[1].replace(/\W+/g, '') ;
retour [
`<option id="${optionId}" value="${o[0]}" `,
`aria-labelledby="${selectLabelledbyIds} ${optionId}">`,
this.localize(o[1]),
'</option>'
].join('') ;
})).
concat('</select>').join('') ;
}
/**
* Créer un élément de couleur de premier plan pour le composant
*
* @return {string}
* Une chaîne HTML.
*
* @private
*/
createElFgColor_() {
const legendId = `captions-text-legend-${this.id_}` ;
retour [
'<fieldset class="vjs-fg-color vjs-track-setting">',
`<legend id= "${legendId}">`,
this.localize('Text'),
</legend>',
this.createElSelect_('color', legendId),
'<span class="vjs-text-opacity vjs-opacity">',
this.createElSelect_('textOpacity', legendId),
'</span>',
'</fieldset>'
].join('') ;
}
/**
* Créer un élément de couleur d'arrière-plan pour le composant
*
* @return {string}
* Une chaîne HTML.
*
* @private
*/
createElBgColor_() {
const legendId = `captions-background-${this.id_}` ;
retour [
'<fieldset class="vjs-bg-color vjs-track-setting">',
`<legend id= "${legendId}">`,
this.localize('Background'),
</legend>',
this.createElSelect_('backgroundColor', legendId),
'<span class="vjs-bg-opacity vjs-opacity">',
this.createElSelect_('backgroundOpacity', legendId),
'</span>',
'</fieldset>'
].join('') ;
}
/**
* Créer un élément de couleur de fenêtre pour le composant
*
* @return {string}
* Une chaîne HTML.
*
* @private
*/
createElWinColor_() {
const legendId = `captions-window-${this.id_}` ;
retour [
'<fieldset class="vjs-window-color vjs-track-setting">',
`<legend id= "${legendId}">`,
this.localize('Window'),
</legend>',
this.createElSelect_('windowColor', legendId),
'<span class="vjs-window-opacity vjs-opacity">',
this.createElSelect_('windowOpacity', legendId),
'</span>',
'</fieldset>'
].join('') ;
}
/**
* Créer des éléments de couleur pour le composant
*
* @return {Element}
* L'élément qui a été créé
*
* @private
*/
createElColors_() {
return createEl('div', {
className : 'vjs-track-settings-colors',
innerHTML : [
this.createElFgColor_(),
this.createElBgColor_(),
this.createElWinColor_()
].join('')
}) ;
}
/**
* Créer des éléments de police pour le composant
*
* @return {Element}
* L'élément qui a été créé.
*
* @private
*/
createElFont_() {
return createEl('div', {
className : 'vjs-track-settings-font',
innerHTML : [
'<fieldset class="vjs-font-percent vjs-track-setting">',
this.createElSelect_('fontPercent', '', 'legend'),
'</fieldset>',
'<fieldset class="vjs-edge-style vjs-track-setting">',
this.createElSelect_('edgeStyle', '', 'legend'),
'</fieldset>',
'<fieldset class="vjs-font-family vjs-track-setting">',
this.createElSelect_('fontFamily', '', 'legend'),
'</fieldset>'
].join('')
}) ;
}
/**
* Créer des contrôles pour le composant
*
* @return {Element}
* L'élément qui a été créé.
*
* @private
*/
createElControls_() {
const defaultsDescription = this.localize('restaurer tous les paramètres aux valeurs par défaut') ;
return createEl('div', {
className : 'vjs-track-settings-controls',
innerHTML : [
`<button type="button" class="vjs-default-button" title="${defaultsDescription}">`,
this.localize('Reset'),
`<span class="vjs-control-text"> ${defaultsDescription}</span>`,
'</button>',
`<button type="button" class="vjs-done-button">${this.localize('Done')}</button>`
].join('')
}) ;
}
content() {
retour [
this.createElColors_(),
this.createElFont_(),
this.createElControls_()
] ;
}
label() {
return this.localize('Boîte de dialogue des paramètres de légende') ;
}
description() {
return this.localize('Début de la fenêtre de dialogue. Escape annulera et fermera la fenêtre") ;
}
buildCSSClass() {
return super.buildCSSClass() + ' vjs-text-track-settings' ;
}
/**
* Obtient un objet contenant les paramètres de la piste de texte (ou null).
*
* @return {Object}
* Un objet contenant des valeurs de configuration analysées à partir du DOM ou du localStorage.
*/
getValues() {
return Obj.reduce(selectConfigs, (accum, config, key) => {
const value = getSelectedOptionValue(this.$(config.selector), config.parser) ;
if (value !== undefined) {
accum[key] = value ;
}
retour accum ;
}, {}) ;
}
/**
* Définit les paramètres de la piste de texte à partir d'un objet de valeurs.
*
* @param {Object} values
* Un objet contenant des valeurs de configuration analysées à partir du DOM ou de localStorage.
*/
setValues(values) {
Obj.each(selectConfigs, (config, key) => {
setSelectedOption(this.$(config.selector), values[key], config.parser) ;
}) ;
}
/**
* Remet tous les éléments `<select>` à leur valeur par défaut.
*/
setDefaults() {
Obj.each(selectConfigs, (config) => {
const index = config.hasOwnProperty('default') ? config.default : 0 ;
this.$(config.selector).selectedIndex = index ;
}) ;
}
/**
* Restaurer les paramètres de la piste de texte à partir de localStorage
*/
restoreSettings() {
laisser les valeurs ;
essayez {
values = JSON.parse(window.localStorage.getItem(LOCAL_STORAGE_KEY)) ;
} catch (err) {
log.warn(err) ;
}
if (values) {
this.setValues(values) ;
}
}
/**
* Enregistrer les paramètres de la piste de texte dans localStorage
*/
saveSettings() {
if (!this.options_.persistTextTrackSettings) {
retour ;
}
const values = this.getValues() ;
essayez {
if (Object.keys(values).length) {
window.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(values)) ;
} else {
window.localStorage.removeItem(LOCAL_STORAGE_KEY) ;
}
} catch (err) {
log.warn(err) ;
}
}
/**
* Mise à jour de l'affichage des paramètres de la piste de texte
*/
updateDisplay() {
const ttDisplay = this.player_.getChild('textTrackDisplay') ;
if (ttDisplay) {
ttDisplay.updateDisplay() ;
}
}
/**
* floutage conditionnel de l'élément et recentrage du bouton des légendes
*
* @private
*/
conditionalBlur_() {
this.previouslyActiveEl_ = null ;
const cb = this.player_.controlBar ;
const subsCapsBtn = cb && cb.subsCapsButton ;
const ccBtn = cb && cb.captionsButton ;
if (subsCapsBtn) {
subsCapsBtn.focus() ;
} else if (ccBtn) {
ccBtn.focus() ;
}
}
}
Component.registerComponent('TextTrackSettings', TextTrackSettings) ;
exporter les paramètres par défaut de TextTrackSettings ;