From d5ce1a0065f1c61f5fc4d8ad4b6a9f9aa20a23ae Mon Sep 17 00:00:00 2001 From: jforbes Date: Wed, 16 Mar 2016 12:44:55 -0400 Subject: [PATCH] Added a button to select from multiple audio tracks Added audio icon Extract TrackButton from Audio and TextTrack buttons Add document comments --- src/css/components/_audio.scss | 3 + src/css/video-js.scss | 1 + .../audio-track-button.js | 64 +++++++++++++++++ .../audio-track-menu-item.js | 71 +++++++++++++++++++ src/js/control-bar/control-bar.js | 2 + .../text-track-controls/text-track-button.js | 34 +++------ src/js/control-bar/track-button.js | 44 ++++++++++++ 7 files changed, 196 insertions(+), 23 deletions(-) create mode 100644 src/css/components/_audio.scss create mode 100644 src/js/control-bar/audio-track-controls/audio-track-button.js create mode 100644 src/js/control-bar/audio-track-controls/audio-track-menu-item.js create mode 100644 src/js/control-bar/track-button.js diff --git a/src/css/components/_audio.scss b/src/css/components/_audio.scss new file mode 100644 index 0000000000..b3894e7d75 --- /dev/null +++ b/src/css/components/_audio.scss @@ -0,0 +1,3 @@ +.video-js .vjs-audio-button { + @extend .vjs-icon-audio; +} diff --git a/src/css/video-js.scss b/src/css/video-js.scss index ee3a18fa3a..62ead5f9ae 100644 --- a/src/css/video-js.scss +++ b/src/css/video-js.scss @@ -35,6 +35,7 @@ @import "components/chapters"; @import "components/descriptions"; @import "components/subtitles"; +@import "components/audio"; @import "components/adaptive"; @import "components/captions-settings"; @import "components/modal-dialog"; diff --git a/src/js/control-bar/audio-track-controls/audio-track-button.js b/src/js/control-bar/audio-track-controls/audio-track-button.js new file mode 100644 index 0000000000..b4f7d5575a --- /dev/null +++ b/src/js/control-bar/audio-track-controls/audio-track-button.js @@ -0,0 +1,64 @@ +/** + * @file audio-track-button.js + */ +import TrackButton from '../track-button.js'; +import Component from '../../component.js'; +import * as Fn from '../../utils/fn.js'; +import AudioTrackMenuItem from './audio-track-menu-item.js'; + +/** + * The base class for buttons that toggle specific text track types (e.g. subtitles) + * + * @param {Player|Object} player + * @param {Object=} options + * @extends TrackButton + * @class AudioTrackButton + */ +class AudioTrackButton extends TrackButton { + constructor(player, options = {}) { + options.tracks = player.audioTracks && player.audioTracks(); + + super(player, options); + + this.el_.setAttribute('aria-label', 'Audio Menu'); + } + + /** + * Allow sub components to stack CSS class names + * + * @return {String} The constructed class name + * @method buildCSSClass + */ + buildCSSClass() { + return `vjs-audio-button ${super.buildCSSClass()}`; + } + + /** + * Create a menu item for each audio track + * + * @return {Array} Array of menu items + * @method createItems + */ + createItems(items = []) { + let tracks = this.player_.audioTracks && this.player_.audioTracks(); + + if (!tracks) { + return items; + } + + for (let i = 0; i < tracks.length; i++) { + let track = tracks[i]; + + items.push(new AudioTrackMenuItem(this.player_, { + // MenuItem is selectable + 'selectable': true, + 'track': track + })); + } + + return items; + } +} + +Component.registerComponent('AudioTrackButton', AudioTrackButton); +export default AudioTrackButton; diff --git a/src/js/control-bar/audio-track-controls/audio-track-menu-item.js b/src/js/control-bar/audio-track-controls/audio-track-menu-item.js new file mode 100644 index 0000000000..fcaf428a43 --- /dev/null +++ b/src/js/control-bar/audio-track-controls/audio-track-menu-item.js @@ -0,0 +1,71 @@ +/** + * @file audio-track-menu-item.js + */ +import MenuItem from '../../menu/menu-item.js'; +import Component from '../../component.js'; +import * as Fn from '../../utils/fn.js'; + +/** + * The audio track menu item + * + * @param {Player|Object} player + * @param {Object=} options + * @extends MenuItem + * @class AudioTrackMenuItem + */ +class AudioTrackMenuItem extends MenuItem { + constructor(player, options) { + let track = options.track; + let tracks = player.audioTracks(); + + // Modify options for parent MenuItem class's init. + options.label = track.label || track.language || 'Unknown'; + options.selected = track.enabled; + + super(player, options); + + this.track = track; + + if (tracks) { + let changeHandler = Fn.bind(this, this.handleTracksChange); + + tracks.addEventListener('change', changeHandler); + this.on('dispose', () => { + tracks.removeEventListener('change', changeHandler); + }); + } + } + + /** + * Handle click on audio track + * + * @method handleClick + */ + handleClick(event) { + let tracks = this.player_.audioTracks(); + + super.handleClick(event); + + if (!tracks) return; + + for (let i = 0; i < tracks.length; i++) { + let track = tracks[i]; + + if (track === this.track) { + track.enabled = true; + } + } + } + + /** + * Handle audio track change + * + * @method handleTracksChange + */ + handleTracksChange(event) { + this.selected(this.track.enabled); + } +} + +Component.registerComponent('AudioTrackMenuItem', AudioTrackMenuItem); +export default AudioTrackMenuItem; diff --git a/src/js/control-bar/control-bar.js b/src/js/control-bar/control-bar.js index f8fc8f757b..7c83d085bc 100644 --- a/src/js/control-bar/control-bar.js +++ b/src/js/control-bar/control-bar.js @@ -19,6 +19,7 @@ import ChaptersButton from './text-track-controls/chapters-button.js'; import DescriptionsButton from './text-track-controls/descriptions-button.js'; import SubtitlesButton from './text-track-controls/subtitles-button.js'; import CaptionsButton from './text-track-controls/captions-button.js'; +import AudioTrackButton from './audio-track-controls/audio-track-button.js'; import PlaybackRateMenuButton from './playback-rate-menu/playback-rate-menu-button.js'; import CustomControlSpacer from './spacer-controls/custom-control-spacer.js'; @@ -63,6 +64,7 @@ ControlBar.prototype.options_ = { 'descriptionsButton', 'subtitlesButton', 'captionsButton', + 'audioTrackButton', 'fullscreenToggle' ] }; diff --git a/src/js/control-bar/text-track-controls/text-track-button.js b/src/js/control-bar/text-track-controls/text-track-button.js index 514a372a71..1decbeec24 100644 --- a/src/js/control-bar/text-track-controls/text-track-button.js +++ b/src/js/control-bar/text-track-controls/text-track-button.js @@ -1,7 +1,7 @@ /** * @file text-track-button.js */ -import MenuButton from '../../menu/menu-button.js'; +import TrackButton from '../track-button.js'; import Component from '../../component.js'; import * as Fn from '../../utils/fn.js'; import TextTrackMenuItem from './text-track-menu-item.js'; @@ -15,32 +15,20 @@ import OffTextTrackMenuItem from './off-text-track-menu-item.js'; * @extends MenuButton * @class TextTrackButton */ -class TextTrackButton extends MenuButton { +class TextTrackButton extends TrackButton { - constructor(player, options){ - super(player, options); - - let tracks = this.player_.textTracks(); - - if (this.items.length <= 1) { - this.hide(); - } + constructor(player, options = {}){ + options.tracks = player.textTracks(); - if (!tracks) { - return; - } - - let updateHandler = Fn.bind(this, this.update); - tracks.addEventListener('removetrack', updateHandler); - tracks.addEventListener('addtrack', updateHandler); - - this.player_.on('dispose', function() { - tracks.removeEventListener('removetrack', updateHandler); - tracks.removeEventListener('addtrack', updateHandler); - }); + super(player, options); } - // Create a menu item for each text track + /** + * Create a menu item for each text track + * + * @return {Array} Array of menu items + * @method createItems + */ createItems(items=[]) { // Add an OFF menu item to turn all tracks off items.push(new OffTextTrackMenuItem(this.player_, { 'kind': this.kind_ })); diff --git a/src/js/control-bar/track-button.js b/src/js/control-bar/track-button.js new file mode 100644 index 0000000000..f482465fa1 --- /dev/null +++ b/src/js/control-bar/track-button.js @@ -0,0 +1,44 @@ +/** + * @file track-button.js + */ +import MenuButton from '../menu/menu-button.js'; +import Component from '../component.js'; +import * as Fn from '../utils/fn.js'; + +/** + * The base class for buttons that toggle specific text track types (e.g. subtitles) + * + * @param {Player|Object} player + * @param {Object=} options + * @extends MenuButton + * @class TrackButton + */ +class TrackButton extends MenuButton { + + constructor(player, options){ + let tracks = options.tracks; + + super(player, options); + + if (this.items.length <= 1) { + this.hide(); + } + + if (!tracks) { + return; + } + + let updateHandler = Fn.bind(this, this.update); + tracks.addEventListener('removetrack', updateHandler); + tracks.addEventListener('addtrack', updateHandler); + + this.player_.on('dispose', function() { + tracks.removeEventListener('removetrack', updateHandler); + tracks.removeEventListener('addtrack', updateHandler); + }); + } + +} + +Component.registerComponent('TrackButton', TrackButton); +export default TrackButton;