Skip to content

Commit

Permalink
refactor: unify all Track and TrackList APIs (#3783)
Browse files Browse the repository at this point in the history
Unify all track-related usage internally.

BREAKING CHANGE: some externally accessibly functions for tracks are now private.
  • Loading branch information
brandonocasey authored and gkatsev committed Jan 19, 2017
1 parent 7bafcc2 commit 49bed07
Show file tree
Hide file tree
Showing 24 changed files with 417 additions and 595 deletions.
8 changes: 2 additions & 6 deletions src/js/control-bar/audio-track-controls/audio-track-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class AudioTrackButton extends TrackButton {
* The key/value store of player options.
*/
constructor(player, options = {}) {
options.tracks = player.audioTracks && player.audioTracks();
options.tracks = player.audioTracks();

super(player, options);

Expand All @@ -49,11 +49,7 @@ class AudioTrackButton extends TrackButton {
* An array of menu items
*/
createItems(items = []) {
const tracks = this.player_.audioTracks && this.player_.audioTracks();

if (!tracks) {
return items;
}
const tracks = this.player_.audioTracks();

for (let i = 0; i < tracks.length; i++) {
const track = tracks[i];
Expand Down
16 changes: 5 additions & 11 deletions src/js/control-bar/audio-track-controls/audio-track-menu-item.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,12 @@ class AudioTrackMenuItem extends MenuItem {

this.track = track;

if (tracks) {
const changeHandler = Fn.bind(this, this.handleTracksChange);
const changeHandler = Fn.bind(this, this.handleTracksChange);

tracks.addEventListener('change', changeHandler);
this.on('dispose', () => {
tracks.removeEventListener('change', changeHandler);
});
}
tracks.addEventListener('change', changeHandler);
this.on('dispose', () => {
tracks.removeEventListener('change', changeHandler);
});
}

/**
Expand All @@ -59,10 +57,6 @@ class AudioTrackMenuItem extends MenuItem {

super.handleClick(event);

if (!tracks) {
return;
}

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

Expand Down
13 changes: 5 additions & 8 deletions src/js/control-bar/text-track-controls/descriptions-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,12 @@ class DescriptionsButton extends TextTrackButton {
this.el_.setAttribute('aria-label', 'Descriptions Menu');

const tracks = player.textTracks();
const changeHandler = Fn.bind(this, this.handleTracksChange);

if (tracks) {
const changeHandler = Fn.bind(this, this.handleTracksChange);

tracks.addEventListener('change', changeHandler);
this.on('dispose', function() {
tracks.removeEventListener('change', changeHandler);
});
}
tracks.addEventListener('change', changeHandler);
this.on('dispose', function() {
tracks.removeEventListener('change', changeHandler);
});
}

/**
Expand Down
4 changes: 0 additions & 4 deletions src/js/control-bar/text-track-controls/text-track-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ class TextTrackButton extends TrackButton {

const tracks = this.player_.textTracks();

if (!tracks) {
return items;
}

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

Expand Down
15 changes: 6 additions & 9 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 @@ -34,23 +34,20 @@ class TextTrackMenuItem extends MenuItem {
super(player, options);

this.track = track;
const changeHandler = Fn.bind(this, this.handleTracksChange);

if (tracks) {
const changeHandler = Fn.bind(this, this.handleTracksChange);

tracks.addEventListener('change', changeHandler);
this.on('dispose', function() {
tracks.removeEventListener('change', changeHandler);
});
}
tracks.addEventListener('change', changeHandler);
this.on('dispose', function() {
tracks.removeEventListener('change', changeHandler);
});

// iOS7 doesn't dispatch change events to TextTrackLists when an
// associated track's mode changes. Without something like
// Object.observe() (also not present on iOS7), it's not
// possible to detect changes to the mode attribute and polyfill
// the change event. As a poor substitute, we manually dispatch
// change events whenever the controls modify the mode.
if (tracks && tracks.onchange === undefined) {
if (tracks.onchange === undefined) {
let event;

this.on(['tap', 'click'], function() {
Expand Down
186 changes: 80 additions & 106 deletions src/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ import mergeOptions from './utils/merge-options.js';
import textTrackConverter from './tracks/text-track-list-converter.js';
import ModalDialog from './modal-dialog';
import Tech from './tech/tech.js';
import AudioTrackList from './tracks/audio-track-list.js';
import VideoTrackList from './tracks/video-track-list.js';
import {ALL as TRACK_TYPES} from './tracks/track-types';

// The following imports are used only to ensure that the corresponding modules
// are always included in the video.js package. Importing the modules will
Expand Down Expand Up @@ -809,14 +808,11 @@ class Player extends Component {
this.isReady_ = false;

// Grab tech-specific options from player options and add source and parent element to use.
const techOptions = assign({
const techOptions = {
source,
'nativeControlsForTouch': this.options_.nativeControlsForTouch,
'playerId': this.id(),
'techId': `${this.id()}_${techName}_api`,
'videoTracks': this.videoTracks_,
'textTracks': this.textTracks_,
'audioTracks': this.audioTracks_,
'autoplay': this.options_.autoplay,
'preload': this.options_.preload,
'loop': this.options_.loop,
Expand All @@ -825,7 +821,15 @@ class Player extends Component {
'language': this.language(),
'playerElIngest': this.playerElIngest_ || false,
'vtt.js': this.options_['vtt.js']
}, this.options_[techName.toLowerCase()]);
};

TRACK_TYPES.names.forEach((name) => {
const props = TRACK_TYPES[name];

techOptions[props.getterName] = this[props.privateName];
});

assign(techOptions, this.options_[techName.toLowerCase()]);

if (this.tag) {
techOptions.tag = this.tag;
Expand Down Expand Up @@ -906,9 +910,11 @@ class Player extends Component {
*/
unloadTech_() {
// Save the current text tracks so that we can reuse the same text tracks with the next tech
this.videoTracks_ = this.videoTracks();
this.textTracks_ = this.textTracks();
this.audioTracks_ = this.audioTracks();
TRACK_TYPES.names.forEach((name) => {
const props = TRACK_TYPES[name];

this[props.privateName] = this[props.getterName]();
});
this.textTracksJson_ = textTrackConverter.textTracksToJson(this.tech_);

this.isReady_ = false;
Expand Down Expand Up @@ -2841,102 +2847,6 @@ class Player extends Component {
return !!this.isAudio_;
}

/**
* Get the {@link VideoTrackList}
*
* @see https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist
*
* @return {VideoTrackList}
* the current video track list
*/
videoTracks() {
// if we have not yet loadTech_, we create videoTracks_
// these will be passed to the tech during loading
if (!this.tech_) {
this.videoTracks_ = this.videoTracks_ || new VideoTrackList();
return this.videoTracks_;
}

return this.tech_.videoTracks();
}

/**
* Get the {@link AudioTrackList}
*
* @see https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist
*
* @return {AudioTrackList}
* the current audio track list
*/
audioTracks() {
// if we have not yet loadTech_, we create videoTracks_
// these will be passed to the tech during loading
if (!this.tech_) {
this.audioTracks_ = this.audioTracks_ || new AudioTrackList();
return this.audioTracks_;
}

return this.tech_.audioTracks();
}

/**
* Get the {@link TextTrackList}
*
* Text tracks are tracks of timed text events.
* - Captions: text displayed over the video
* for the hearing impaired
* - Subtitles: text displayed over the video for
* those who don't understand language in the video
* - Chapters: text displayed in a menu allowing the user to jump
* to particular points (chapters) in the video
* - Descriptions: (not yet implemented) audio descriptions that are read back to
* the user by a screen reading device
*
* @see http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks
*
* @return {TextTrackList|undefined}
* The current TextTrackList or undefined if
* or undefined if we don't have a tech
*/
textTracks() {
// cannot use techGet_ directly because it checks to see whether the tech is ready.
// Flash is unlikely to be ready in time but textTracks should still work.
if (this.tech_) {
return this.tech_.textTracks();
}
}

/**
* Get the "remote" {@link TextTrackList}. Remote Text Tracks
* are tracks that were added to the HTML video element and can
* be removed, whereas normal texttracks cannot be removed.
*
*
* @return {TextTrackList|undefined}
* The current remote text track list or undefined
* if we don't have a tech
*/
remoteTextTracks() {
if (this.tech_) {
return this.tech_.remoteTextTracks();
}
}

/**
* Get the "remote" {@link HTMLTrackElementList}.
* This gives the user all of the DOM elements that match up
* with the remote {@link TextTrackList}.
*
* @return {HTMLTrackElementList}
* The current remote text track list elements
* or undefined if we don't have a tech
*/
remoteTextTrackEls() {
if (this.tech_) {
return this.tech_.remoteTextTrackEls();
}
}

/**
* A helper method for adding a {@link TextTrack} to our
* {@link TextTrackList}.
Expand Down Expand Up @@ -3194,6 +3104,70 @@ class Player extends Component {
}
}

/**
* Get the {@link VideoTrackList}
* @link https://html.spec.whatwg.org/multipage/embedded-content.html#videotracklist
*
* @return {VideoTrackList}
* the current video track list
*
* @method Player.prototype.videoTracks
*/

/**
* Get the {@link AudioTrackList}
* @link https://html.spec.whatwg.org/multipage/embedded-content.html#audiotracklist
*
* @return {AudioTrackList}
* the current audio track list
*
* @method Player.prototype.audioTracks
*/

/**
* Get the {@link TextTrackList}
*
* @link http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#dom-media-texttracks
*
* @return {TextTrackList}
* the current text track list
*
* @method Player.prototype.textTracks
*/

/**
* Get the remote {@link TextTrackList}
*
* @return {TextTrackList}
* The current remote text track list
*
* @method Player.prototype.textTracks
*/

/**
* Get the remote {@link HTMLTrackElementList} tracks.
*
* @return {HTMLTrackElementList}
* The current remote text track element list
*
* @method Player.prototype.remoteTextTrackEls
*/

TRACK_TYPES.names.forEach(function(name) {
const props = TRACK_TYPES[name];

Player.prototype[props.getterName] = function() {
if (this.tech_) {
return this.tech_[props.getterName]();
}

// if we have not yet loadTech_, we create {video,audio,text}Tracks_
// these will be passed to the tech during loading
this[props.privateName] = this[props.privateName] || new props.ListClass();
return this[props.privateName];
};
});

/**
* Global player list
*
Expand Down
Loading

0 comments on commit 49bed07

Please sign in to comment.