/** * @file mute-toggle.js */ import Button from '../button'; import Component from '../component'; import * as Dom from '../utils/dom.js'; import checkMuteSupport from './volume-control/check-mute-support'; import * as browser from '../utils/browser.js'; /** @import Player from './player' */ /** * A button component for muting the audio. * * @extends Button */ class MuteToggle extends Button { /** * Creates an instance of this class. * * @param {Player} player * The `Player` that this class should be attached to. * * @param {Object} [options] * The key/value store of player options. */ constructor(player, options) { super(player, options); // hide this control if volume support is missing checkMuteSupport(this, player); this.on(player, ['loadstart', 'volumechange'], (e) => this.update(e)); } /** * Builds the default DOM `className`. * * @return {string} * The DOM `className` for this object. */ buildCSSClass() { return `vjs-mute-control ${super.buildCSSClass()}`; } /** * This gets called when an `MuteToggle` is "clicked". See * {@link ClickableComponent} for more detailed information on what a click can be. * * @param {Event} [event] * The `keydown`, `tap`, or `click` event that caused this function to be * called. * * @listens tap * @listens click */ handleClick(event) { const vol = this.player_.volume(); const lastVolume = this.player_.lastVolume_(); if (vol === 0) { const volumeToSet = lastVolume < 0.1 ? 0.1 : lastVolume; this.player_.volume(volumeToSet); this.player_.muted(false); } else { this.player_.muted(this.player_.muted() ? false : true); } } /** * Update the `MuteToggle` button based on the state of `volume` and `muted` * on the player. * * @param {Event} [event] * The {@link Player#loadstart} event if this function was called * through an event. * * @listens Player#loadstart * @listens Player#volumechange */ update(event) { this.updateIcon_(); this.updateControlText_(); } /** * Update the appearance of the `MuteToggle` icon. * * Possible states (given `level` variable below): * - 0: crossed out * - 1: zero bars of volume * - 2: one bar of volume * - 3: two bars of volume * * @private */ updateIcon_() { const vol = this.player_.volume(); let level = 3; this.setIcon('volume-high'); // in iOS when a player is loaded with muted attribute // and volume is changed with a native mute button // we want to make sure muted state is updated if (browser.IS_IOS && this.player_.tech_ && this.player_.tech_.el_) { this.player_.muted(this.player_.tech_.el_.muted); } if (vol === 0 || this.player_.muted()) { this.setIcon('volume-mute'); level = 0; } else if (vol < 0.33) { this.setIcon('volume-low'); level = 1; } else if (vol < 0.67) { this.setIcon('volume-medium'); level = 2; } Dom.removeClass(this.el_, [0, 1, 2, 3].reduce((str, i) => str + `${i ? ' ' : ''}vjs-vol-${i}`, '')); Dom.addClass(this.el_, `vjs-vol-${level}`); } /** * If `muted` has changed on the player, update the control text * (`title` attribute on `vjs-mute-control` element and content of * `vjs-control-text` element). * * @private */ updateControlText_() { const soundOff = this.player_.muted() || this.player_.volume() === 0; const text = soundOff ? 'Unmute' : 'Mute'; if (this.controlText() !== text) { this.controlText(text); } } } /** * The text that should display over the `MuteToggle`s controls. Added for localization. * * @type {string} * @protected */ MuteToggle.prototype.controlText_ = 'Mute'; Component.registerComponent('MuteToggle', MuteToggle); export default MuteToggle;