Skip to content

Commit

Permalink
feat: Combine captions and subtitles tracks control (#4028)
Browse files Browse the repository at this point in the history
  • Loading branch information
mister-ben authored and gkatsev committed Mar 2, 2017
1 parent f95815b commit 74eb5d4
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 30 deletions.
68 changes: 68 additions & 0 deletions sandbox/combined-tracks.html.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta charset="utf-8" />
<title>Video.js Sandbox</title>

<!-- Add ES5 shim and sham for IE8 -->
<script src="../build/temp/ie8/videojs-ie8.js"></script>

<!-- Load the source files -->
<link href="../build/temp/video-js.css" rel="stylesheet" type="text/css">
<script src="../build/temp/video.js"></script>
<script src="../node_modules/videojs-flash/dist/videojs-flash.js"></script>

<!-- Set the location of the flash SWF -->
<script>
videojs.options.flash.swf = '../build/temp/video-js.swf';
</script>
</head>
<body>
<div style="background-color:#eee; border: 1px solid #777; padding: 10px; margin-bottom: 20px; font-size: .8em; line-height: 1.5em; font-family: Verdana, sans-serif;">
<p>You can use /sandbox/ for writing and testing your own code. Nothing in /sandbox/ will get checked into the repo, except files that end in .example (so don't edit or add those files). To get started make a copy of index.html.example and rename it to index.html.</p>
<pre>cp sandbox/index.html.example sandbox/index.html</pre>
<pre>npm run start</pre>
<pre>open http://localhost:9999/sandbox/index.html</pre>
</div>

<video id="vid1" class="video-js vjs-default-skin" lang="en" controls preload="auto" width="640" height="264" poster="http://vjs.zencdn.net/v/oceans.png">
<source src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/ed_hd.mp4" type="video/mp4">
<source src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/ed_hd.ogg" type="video/ogg">
<track kind="captions" src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/captions.en.vtt" srclang="en" label="English"></track><!-- Tracks need an ending tag thanks to IE9 -->
<track kind="subtitles" src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/captions.ar.vtt" srclang="ar" label="Arabic"></track><!-- Tracks need an ending tag thanks to IE9 -->
<track kind="subtitles" src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/captions.sv.vtt" srclang="sv" label="Swedish"></track><!-- Tracks need an ending tag thanks to IE9 -->
<track kind="subtitles" src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/captions.ru.vtt" srclang="ru" label="Russian"></track><!-- Tracks need an ending tag thanks to IE9 -->
<track kind="subtitles" src="//d2zihajmogu5jn.cloudfront.net/elephantsdream/captions.ja.vtt" srclang="ja" label="Japanese"></track><!-- Tracks need an ending tag thanks to IE9 -->
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
</video>
<p>This player has the captions-only CpationsButton, the subtiles-only subtitlesButton and the subsCapsButton which shows both kinds. Typically you'll use either just the subsCapsButton alone, or one or both of the captionsButton and subtitlesButton.</p>
<script>
var vid = document.getElementById("vid1");
var player = videojs(vid, {
controlBar: {
children: [
'playToggle',
'volumePanel',
'currentTimeDisplay',
'timeDivider',
'durationDisplay',
'progressControl',
'liveDisplay',
'remainingTimeDisplay',
'customControlSpacer',
'playbackRateMenuButton',
'chaptersButton',
'descriptionsButton',
'subtitlesButton',
'captionsButton',
'subsCapsButton',
'audioTrackButton',
'fullscreenToggle'
]
}
});
console.log(player.language());
</script>

</body>
</html>
22 changes: 22 additions & 0 deletions src/css/components/_subs-caps.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// North America uses 'CC' icon
.video-js:lang(en) .vjs-subs-caps-button .vjs-icon-placeholder,
.video-js:lang(fr-CA) .vjs-subs-caps-button .vjs-icon-placeholder {
@extend .vjs-icon-captions;
}

// ROW uses 'subtitles'
// Double selector because @extend puts these rules above the captions icon
.video-js .vjs-subs-caps-button .vjs-icon-placeholder,
.video-js.video-js:lang(en-GB) .vjs-subs-caps-button .vjs-icon-placeholder,
.video-js.video-js:lang(en-IE) .vjs-subs-caps-button .vjs-icon-placeholder,
.video-js.video-js:lang(en-AU) .vjs-subs-caps-button .vjs-icon-placeholder,
.video-js.video-js:lang(en-NZ) .vjs-subs-caps-button .vjs-icon-placeholder {
@extend .vjs-icon-subtitles;
}

.video-js .vjs-subs-caps-button + .vjs-menu .vjs-captions-menu-item .vjs-menu-item-text:after {
content: " \f10d";
font-family: VideoJS;
vertical-align: bottom;
font-size: 1.5em;
}
1 change: 1 addition & 0 deletions src/css/video-js.scss
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
@import "components/chapters";
@import "components/descriptions";
@import "components/subtitles";
@import "components/subs-caps";
@import "components/audio";
@import "components/adaptive";
@import "components/captions-settings";
Expand Down
4 changes: 2 additions & 2 deletions src/js/control-bar/control-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import './text-track-controls/chapters-button.js';
import './text-track-controls/descriptions-button.js';
import './text-track-controls/subtitles-button.js';
import './text-track-controls/captions-button.js';
import './text-track-controls/subs-caps-button.js';
import './audio-track-controls/audio-track-button.js';
import './playback-rate-menu/playback-rate-menu-button.js';
import './spacer-controls/custom-control-spacer.js';
Expand Down Expand Up @@ -66,8 +67,7 @@ ControlBar.prototype.options_ = {
'playbackRateMenuButton',
'chaptersButton',
'descriptionsButton',
'subtitlesButton',
'captionsButton',
'subsCapsButton',
'audioTrackButton',
'fullscreenToggle'
]
Expand Down
14 changes: 12 additions & 2 deletions src/js/control-bar/text-track-controls/off-text-track-menu-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,21 @@ class OffTextTrackMenuItem extends TextTrackMenuItem {
options.track = {
player,
kind: options.kind,
label: options.kind + ' off',
kinds: options.kinds,
default: false,
mode: 'disabled'
};

if (!options.kinds) {
options.kinds = [options.kind];
}

if (options.label) {
options.track.label = options.label;
} else {
options.track.label = options.kinds.join(' and ') + ' off';
}

// MenuItem is selectable
options.selectable = true;

Expand All @@ -51,7 +61,7 @@ class OffTextTrackMenuItem extends TextTrackMenuItem {
for (let i = 0, l = tracks.length; i < l; i++) {
const track = tracks[i];

if (track.kind === this.track.kind && track.mode === 'showing') {
if ((this.options_.kinds.indexOf(track.kind) > -1) && track.mode === 'showing') {
selected = false;
break;
}
Expand Down
102 changes: 102 additions & 0 deletions src/js/control-bar/text-track-controls/subs-caps-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* @file sub-caps-button.js
*/
import TextTrackButton from './text-track-button.js';
import Component from '../../component.js';
import CaptionSettingsMenuItem from './caption-settings-menu-item.js';
import toTitleCase from '../../utils/to-title-case.js';
/**
* The button component for toggling and selecting captions and/or subtitles
*
* @extends TextTrackButton
*/
class SubsCapsButton extends TextTrackButton {

constructor(player, options = {}) {
super(player, options);

// Although North America uses "captions" in most cases for
// "captions and subtitles" other locales use "subtitles"
this.label_ = 'subtitles';
if (['en', 'en-us', 'en-ca', 'fr-ca'].indexOf(this.player_.language_) > -1) {
this.label_ = 'captions';
}
this.menuButton_.controlText(toTitleCase(this.label_));

}

/**
* Builds the default DOM `className`.
*
* @return {string}
* The DOM `className` for this object.
*/
buildCSSClass() {
return `vjs-subs-caps-button ${super.buildCSSClass()}`;
}

/**
* Update caption menu items
*
* @param {EventTarget~Event} [event]
* The `addtrack` or `removetrack` event that caused this function to be
* called.
*
* @listens TextTrackList#addtrack
* @listens TextTrackList#removetrack
*/
update(event) {
let threshold = 2;

super.update();

// if native, then threshold is 1 because no settings button
if (this.player().tech_ && this.player().tech_.featuresNativeTextTracks) {
threshold = 1;
}

if (this.items && this.items.length > threshold) {
this.show();
} else {
this.hide();
}
}

/**
* Create caption/subtitles menu items
*
* @return {CaptionSettingsMenuItem[]}
* The array of current menu items.
*/
createItems() {
let items = [];

if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks)) {
items.push(new CaptionSettingsMenuItem(this.player_, {kind: this.label_}));
}

items = super.createItems(items);
return items;
}

}

/**
* `kind`s of TextTrack to look for to associate it with this menu.
*
* @type {array}
* @private
*/
SubsCapsButton.prototype.kinds_ = ['captions', 'subtitles'];

/**
* The text that should display over the `SubsCapsButton`s controls.
*
*
* @type {string}
* @private
*/
SubsCapsButton.prototype.controlText_ = 'Subtitles';

Component.registerComponent('SubsCapsButton', SubsCapsButton);
export default SubsCapsButton;
29 changes: 24 additions & 5 deletions src/js/control-bar/text-track-controls/text-track-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class TextTrackButton extends TrackButton {
options.tracks = player.textTracks();

super(player, options);

if (!Array.isArray(this.kinds_)) {
this.kinds_ = [this.kind_];
}
}

/**
Expand All @@ -38,21 +42,36 @@ class TextTrackButton extends TrackButton {
* Array of menu items that were created
*/
createItems(items = []) {

// Label is an overide for the [track] off label
// USed to localise captions/subtitles
let label;

if (this.label_) {
label = `${this.label_} off`;
}
// Add an OFF menu item to turn all tracks off
items.push(new OffTextTrackMenuItem(this.player_, {kind: this.kind_}));
items.push(new OffTextTrackMenuItem(this.player_, {
kinds: this.kinds_,
kind: this.kind_,
label
}));

const tracks = this.player_.textTracks();

for (let i = 0; i < tracks.length; i++) {
const track = tracks[i];

// only add tracks that are of the appropriate kind and have a label
if (track.kind === this.kind_) {
items.push(new TextTrackMenuItem(this.player_, {
// only add tracks that are of an appropriate kind and have a label
if (this.kinds_.indexOf(track.kind) > -1) {
const item = new TextTrackMenuItem(this.player_, {
track,
// MenuItem is selectable
selectable: true
}));
});

item.addClass(`vjs-${track.kind}-menu-item`);
items.push(item);
}
}

Expand Down
11 changes: 6 additions & 5 deletions src/js/control-bar/text-track-controls/text-track-menu-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,13 @@ class TextTrackMenuItem extends MenuItem {
*/
handleClick(event) {
const kind = this.track.kind;
let kinds = this.track.kinds;
const tracks = this.player_.textTracks();

if (!kinds) {
kinds = [kind];
}

super.handleClick(event);

if (!tracks) {
Expand All @@ -94,11 +99,7 @@ class TextTrackMenuItem extends MenuItem {
for (let i = 0; i < tracks.length; i++) {
const track = tracks[i];

if (track.kind !== kind) {
continue;
}

if (track === this.track) {
if (track === this.track && (kinds.indexOf(track.kind) > -1)) {
track.mode = 'showing';
} else {
track.mode = 'disabled';
Expand Down
Loading

0 comments on commit 74eb5d4

Please sign in to comment.