mirror of
https://github.com/videojs/video.js.git
synced 2025-01-02 06:32:07 +02:00
@BrandonOCasey converted remaining text-track modules to ES6. closes #3130
This commit is contained in:
parent
d9a0a4503c
commit
cb3d709237
@ -3,6 +3,7 @@ CHANGELOG
|
||||
|
||||
## HEAD (Unreleased)
|
||||
* @gkatsev updated videojs badges in the README ([view](https://github.com/videojs/video.js/pull/3134))
|
||||
* @BrandonOCasey converted remaining text-track modules to ES6 ([view](https://github.com/videojs/video.js/pull/3130))
|
||||
|
||||
--------------------
|
||||
|
||||
|
@ -4,7 +4,8 @@
|
||||
import * as browser from '../utils/browser.js';
|
||||
import document from 'global/document';
|
||||
|
||||
/*
|
||||
/**
|
||||
* A List of text track cues as defined in:
|
||||
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist
|
||||
*
|
||||
* interface TextTrackCueList {
|
||||
@ -12,72 +13,93 @@ import document from 'global/document';
|
||||
* getter TextTrackCue (unsigned long index);
|
||||
* TextTrackCue? getCueById(DOMString id);
|
||||
* };
|
||||
*
|
||||
* @param {Array} cues A list of cues to be initialized with
|
||||
* @class TextTrackCueList
|
||||
*/
|
||||
|
||||
function TextTrackCueList (cues) {
|
||||
let list = this;
|
||||
class TextTrackCueList {
|
||||
constructor(cues) {
|
||||
let list = this;
|
||||
|
||||
if (browser.IS_IE8) {
|
||||
list = document.createElement('custom');
|
||||
if (browser.IS_IE8) {
|
||||
list = document.createElement('custom');
|
||||
|
||||
for (let prop in TextTrackCueList.prototype) {
|
||||
if (prop !== 'constructor') {
|
||||
list[prop] = TextTrackCueList.prototype[prop];
|
||||
for (let prop in TextTrackCueList.prototype) {
|
||||
if (prop !== 'constructor') {
|
||||
list[prop] = TextTrackCueList.prototype[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextTrackCueList.prototype.setCues_.call(list, cues);
|
||||
|
||||
Object.defineProperty(list, 'length', {
|
||||
get() {
|
||||
return this.length_;
|
||||
}
|
||||
});
|
||||
|
||||
if (browser.IS_IE8) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A setter for cues in this list
|
||||
*
|
||||
* @param {Array} cues an array of cues
|
||||
* @method setCues_
|
||||
* @private
|
||||
*/
|
||||
setCues_(cues) {
|
||||
let oldLength = this.length || 0;
|
||||
let i = 0;
|
||||
let l = cues.length;
|
||||
|
||||
this.cues_ = cues;
|
||||
this.length_ = cues.length;
|
||||
|
||||
let defineProp = function(index) {
|
||||
if (!('' + index in this)) {
|
||||
Object.defineProperty(this, '' + index, {
|
||||
get() {
|
||||
return this.cues_[index];
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (oldLength < l) {
|
||||
i = oldLength;
|
||||
|
||||
for (; i < l; i++) {
|
||||
defineProp.call(this, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextTrackCueList.prototype.setCues_.call(list, cues);
|
||||
/**
|
||||
* Get a cue that is currently in the Cue list by id
|
||||
*
|
||||
* @param {String} id
|
||||
* @method getCueById
|
||||
* @return {Object} a single cue
|
||||
*/
|
||||
getCueById(id) {
|
||||
let result = null;
|
||||
|
||||
Object.defineProperty(list, 'length', {
|
||||
get: function() {
|
||||
return this.length_;
|
||||
for (let i = 0, l = this.length; i < l; i++) {
|
||||
let cue = this[i];
|
||||
|
||||
if (cue.id === id) {
|
||||
result = cue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (browser.IS_IE8) {
|
||||
return list;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
TextTrackCueList.prototype.setCues_ = function(cues) {
|
||||
let oldLength = this.length || 0;
|
||||
let i = 0;
|
||||
let l = cues.length;
|
||||
|
||||
this.cues_ = cues;
|
||||
this.length_ = cues.length;
|
||||
|
||||
let defineProp = function(i) {
|
||||
if (!(''+i in this)) {
|
||||
Object.defineProperty(this, '' + i, {
|
||||
get: function() {
|
||||
return this.cues_[i];
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (oldLength < l) {
|
||||
i = oldLength;
|
||||
|
||||
for(; i < l; i++) {
|
||||
defineProp.call(this, i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TextTrackCueList.prototype.getCueById = function(id) {
|
||||
let result = null;
|
||||
for (let i = 0, l = this.length; i < l; i++) {
|
||||
let cue = this[i];
|
||||
if (cue.id === id) {
|
||||
result = cue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export default TextTrackCueList;
|
||||
|
@ -1,27 +1,39 @@
|
||||
/**
|
||||
* @file text-track-enums.js
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode
|
||||
*
|
||||
* enum TextTrackMode { "disabled", "hidden", "showing" };
|
||||
*/
|
||||
var TextTrackMode = {
|
||||
'disabled': 'disabled',
|
||||
'hidden': 'hidden',
|
||||
'showing': 'showing'
|
||||
const TextTrackMode = {
|
||||
disabled: 'disabled',
|
||||
hidden: 'hidden',
|
||||
showing: 'showing'
|
||||
};
|
||||
|
||||
/*
|
||||
/**
|
||||
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackkind
|
||||
*
|
||||
* enum TextTrackKind { "subtitles", "captions", "descriptions", "chapters", "metadata" };
|
||||
* enum TextTrackKind {
|
||||
* "subtitles",
|
||||
* "captions",
|
||||
* "descriptions",
|
||||
* "chapters",
|
||||
* "metadata"
|
||||
* };
|
||||
*/
|
||||
var TextTrackKind = {
|
||||
'subtitles': 'subtitles',
|
||||
'captions': 'captions',
|
||||
'descriptions': 'descriptions',
|
||||
'chapters': 'chapters',
|
||||
'metadata': 'metadata'
|
||||
const TextTrackKind = {
|
||||
subtitles: 'subtitles',
|
||||
captions: 'captions',
|
||||
descriptions: 'descriptions',
|
||||
chapters: 'chapters',
|
||||
metadata: 'metadata'
|
||||
};
|
||||
|
||||
/* jshint ignore:start */
|
||||
// we ignore jshint here because it does not see
|
||||
// TextTrackMode or TextTrackKind as defined here somehow...
|
||||
export { TextTrackMode, TextTrackKind };
|
||||
/* jshint ignore:end */
|
||||
|
@ -6,7 +6,8 @@ import * as Fn from '../utils/fn.js';
|
||||
import * as browser from '../utils/browser.js';
|
||||
import document from 'global/document';
|
||||
|
||||
/*
|
||||
/**
|
||||
* A text track list as defined in:
|
||||
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist
|
||||
*
|
||||
* interface TextTrackList : EventTarget {
|
||||
@ -18,50 +19,140 @@ import document from 'global/document';
|
||||
* attribute EventHandler onaddtrack;
|
||||
* attribute EventHandler onremovetrack;
|
||||
* };
|
||||
*
|
||||
* @param {Track[]} tracks A list of tracks to initialize the list with
|
||||
* @extends EventTarget
|
||||
* @class TextTrackList
|
||||
*/
|
||||
function TextTrackList (tracks) {
|
||||
let list = this;
|
||||
|
||||
if (browser.IS_IE8) {
|
||||
list = document.createElement('custom');
|
||||
class TextTrackList extends EventTarget {
|
||||
constructor(tracks = []) {
|
||||
super();
|
||||
let list = this;
|
||||
|
||||
for (let prop in TextTrackList.prototype) {
|
||||
if (prop !== 'constructor') {
|
||||
list[prop] = TextTrackList.prototype[prop];
|
||||
if (browser.IS_IE8) {
|
||||
list = document.createElement('custom');
|
||||
|
||||
for (let prop in TextTrackList.prototype) {
|
||||
if (prop !== 'constructor') {
|
||||
list[prop] = TextTrackList.prototype[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tracks = tracks || [];
|
||||
list.tracks_ = [];
|
||||
list.tracks_ = [];
|
||||
|
||||
Object.defineProperty(list, 'length', {
|
||||
get: function() {
|
||||
return this.tracks_.length;
|
||||
Object.defineProperty(list, 'length', {
|
||||
get() {
|
||||
return this.tracks_.length;
|
||||
}
|
||||
});
|
||||
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
list.addTrack_(tracks[i]);
|
||||
}
|
||||
});
|
||||
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
list.addTrack_(tracks[i]);
|
||||
if (browser.IS_IE8) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
if (browser.IS_IE8) {
|
||||
return list;
|
||||
/**
|
||||
* Add TextTrack from TextTrackList
|
||||
*
|
||||
* @param {TextTrack} track
|
||||
* @method addTrack_
|
||||
* @private
|
||||
*/
|
||||
addTrack_(track) {
|
||||
let index = this.tracks_.length;
|
||||
|
||||
if (!('' + index in this)) {
|
||||
Object.defineProperty(this, index, {
|
||||
get() {
|
||||
return this.tracks_[index];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
track.addEventListener('modechange', Fn.bind(this, function() {
|
||||
this.trigger('change');
|
||||
}));
|
||||
this.tracks_.push(track);
|
||||
|
||||
this.trigger({
|
||||
track,
|
||||
type: 'addtrack'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove TextTrack from TextTrackList
|
||||
* NOTE: Be mindful of what is passed in as it may be a HTMLTrackElement
|
||||
*
|
||||
* @param {TextTrack} rtrack
|
||||
* @method removeTrack_
|
||||
* @private
|
||||
*/
|
||||
removeTrack_(rtrack) {
|
||||
let track;
|
||||
|
||||
for (let i = 0, l = this.length; i < l; i++) {
|
||||
if (this[i] === rtrack) {
|
||||
track = this[i];
|
||||
if (track.off) {
|
||||
track.off();
|
||||
}
|
||||
|
||||
this.tracks_.splice(i, 1);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!track) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.trigger({
|
||||
track,
|
||||
type: 'removetrack'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a TextTrack from TextTrackList by a tracks id
|
||||
*
|
||||
* @param {String} id - the id of the track to get
|
||||
* @method getTrackById
|
||||
* @return {TextTrack}
|
||||
* @private
|
||||
*/
|
||||
getTrackById(id) {
|
||||
let result = null;
|
||||
|
||||
for (let i = 0, l = this.length; i < l; i++) {
|
||||
let track = this[i];
|
||||
|
||||
if (track.id === id) {
|
||||
result = track;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
TextTrackList.prototype = Object.create(EventTarget.prototype);
|
||||
TextTrackList.prototype.constructor = TextTrackList;
|
||||
|
||||
/*
|
||||
/**
|
||||
* change - One or more tracks in the track list have been enabled or disabled.
|
||||
* addtrack - A track has been added to the track list.
|
||||
* removetrack - A track has been removed from the track list.
|
||||
*/
|
||||
TextTrackList.prototype.allowedEvents_ = {
|
||||
'change': 'change',
|
||||
'addtrack': 'addtrack',
|
||||
'removetrack': 'removetrack'
|
||||
change: 'change',
|
||||
addtrack: 'addtrack',
|
||||
removetrack: 'removetrack'
|
||||
};
|
||||
|
||||
// emulate attribute EventHandler support to allow for feature detection
|
||||
@ -69,80 +160,4 @@ for (let event in TextTrackList.prototype.allowedEvents_) {
|
||||
TextTrackList.prototype['on' + event] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add TextTrack from TextTrackList
|
||||
*
|
||||
* @param {TextTrack} track
|
||||
* @method addTrack_
|
||||
* @private
|
||||
*/
|
||||
TextTrackList.prototype.addTrack_ = function(track) {
|
||||
let index = this.tracks_.length;
|
||||
if (!(''+index in this)) {
|
||||
Object.defineProperty(this, index, {
|
||||
get: function() {
|
||||
return this.tracks_[index];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
track.addEventListener('modechange', Fn.bind(this, function() {
|
||||
this.trigger('change');
|
||||
}));
|
||||
this.tracks_.push(track);
|
||||
|
||||
this.trigger({
|
||||
type: 'addtrack',
|
||||
track: track
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove TextTrack from TextTrackList
|
||||
* NOTE: Be mindful of what is passed in as it may be a HTMLTrackElement
|
||||
*
|
||||
* @param {TextTrack} rtrack
|
||||
* @method removeTrack_
|
||||
* @private
|
||||
*/
|
||||
TextTrackList.prototype.removeTrack_ = function(rtrack) {
|
||||
let track;
|
||||
|
||||
for (let i = 0, l = this.length; i < l; i++) {
|
||||
if (this[i] === rtrack) {
|
||||
track = this[i];
|
||||
if (track.off) {
|
||||
track.off();
|
||||
}
|
||||
|
||||
this.tracks_.splice(i, 1);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!track) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.trigger({
|
||||
type: 'removetrack',
|
||||
track: track
|
||||
});
|
||||
};
|
||||
|
||||
TextTrackList.prototype.getTrackById = function(id) {
|
||||
let result = null;
|
||||
|
||||
for (let i = 0, l = this.length; i < l; i++) {
|
||||
let track = this[i];
|
||||
if (track.id === id) {
|
||||
result = track;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export default TextTrackList;
|
||||
|
@ -13,229 +13,16 @@ import window from 'global/window';
|
||||
import { isCrossOrigin } from '../utils/url.js';
|
||||
import XHR from 'xhr';
|
||||
|
||||
/*
|
||||
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack
|
||||
/**
|
||||
* takes a webvtt file contents and parses it into cues
|
||||
*
|
||||
* interface TextTrack : EventTarget {
|
||||
* readonly attribute TextTrackKind kind;
|
||||
* readonly attribute DOMString label;
|
||||
* readonly attribute DOMString language;
|
||||
*
|
||||
* readonly attribute DOMString id;
|
||||
* readonly attribute DOMString inBandMetadataTrackDispatchType;
|
||||
*
|
||||
* attribute TextTrackMode mode;
|
||||
*
|
||||
* readonly attribute TextTrackCueList? cues;
|
||||
* readonly attribute TextTrackCueList? activeCues;
|
||||
*
|
||||
* void addCue(TextTrackCue cue);
|
||||
* void removeCue(TextTrackCue cue);
|
||||
*
|
||||
* attribute EventHandler oncuechange;
|
||||
* };
|
||||
* @param {String} srcContent webVTT file contents
|
||||
* @param {Track} track track to addcues to
|
||||
*/
|
||||
function TextTrack (options={}) {
|
||||
if (!options.tech) {
|
||||
throw new Error('A tech was not provided.');
|
||||
}
|
||||
|
||||
let tt = this;
|
||||
if (browser.IS_IE8) {
|
||||
tt = document.createElement('custom');
|
||||
|
||||
for (let prop in TextTrack.prototype) {
|
||||
if (prop !== 'constructor') {
|
||||
tt[prop] = TextTrack.prototype[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tt.tech_ = options.tech;
|
||||
|
||||
let mode = TextTrackEnum.TextTrackMode[options['mode']] || 'disabled';
|
||||
let kind = TextTrackEnum.TextTrackKind[options['kind']] || 'subtitles';
|
||||
let label = options['label'] || '';
|
||||
let language = options['language'] || options['srclang'] || '';
|
||||
let id = options['id'] || 'vjs_text_track_' + Guid.newGUID();
|
||||
|
||||
if (kind === 'metadata' || kind === 'chapters') {
|
||||
mode = 'hidden';
|
||||
}
|
||||
|
||||
tt.cues_ = [];
|
||||
tt.activeCues_ = [];
|
||||
|
||||
let cues = new TextTrackCueList(tt.cues_);
|
||||
let activeCues = new TextTrackCueList(tt.activeCues_);
|
||||
|
||||
let changed = false;
|
||||
let timeupdateHandler = Fn.bind(tt, function() {
|
||||
this['activeCues'];
|
||||
if (changed) {
|
||||
this['trigger']('cuechange');
|
||||
changed = false;
|
||||
}
|
||||
});
|
||||
if (mode !== 'disabled') {
|
||||
tt.tech_.on('timeupdate', timeupdateHandler);
|
||||
}
|
||||
|
||||
Object.defineProperty(tt, 'kind', {
|
||||
get: function() {
|
||||
return kind;
|
||||
},
|
||||
set: Function.prototype
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'label', {
|
||||
get: function() {
|
||||
return label;
|
||||
},
|
||||
set: Function.prototype
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'language', {
|
||||
get: function() {
|
||||
return language;
|
||||
},
|
||||
set: Function.prototype
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'id', {
|
||||
get: function() {
|
||||
return id;
|
||||
},
|
||||
set: Function.prototype
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'mode', {
|
||||
get: function() {
|
||||
return mode;
|
||||
},
|
||||
set: function(newMode) {
|
||||
if (!TextTrackEnum.TextTrackMode[newMode]) {
|
||||
return;
|
||||
}
|
||||
mode = newMode;
|
||||
if (mode === 'showing') {
|
||||
this.tech_.on('timeupdate', timeupdateHandler);
|
||||
}
|
||||
this.trigger('modechange');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'cues', {
|
||||
get: function() {
|
||||
if (!this.loaded_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return cues;
|
||||
},
|
||||
set: Function.prototype
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'activeCues', {
|
||||
get: function() {
|
||||
if (!this.loaded_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this['cues'].length === 0) {
|
||||
return activeCues; // nothing to do
|
||||
}
|
||||
|
||||
let ct = this.tech_.currentTime();
|
||||
let active = [];
|
||||
|
||||
for (let i = 0, l = this['cues'].length; i < l; i++) {
|
||||
let cue = this['cues'][i];
|
||||
if (cue['startTime'] <= ct && cue['endTime'] >= ct) {
|
||||
active.push(cue);
|
||||
} else if (cue['startTime'] === cue['endTime'] && cue['startTime'] <= ct && cue['startTime'] + 0.5 >= ct) {
|
||||
active.push(cue);
|
||||
}
|
||||
}
|
||||
|
||||
changed = false;
|
||||
|
||||
if (active.length !== this.activeCues_.length) {
|
||||
changed = true;
|
||||
} else {
|
||||
for (let i = 0; i < active.length; i++) {
|
||||
if (indexOf.call(this.activeCues_, active[i]) === -1) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.activeCues_ = active;
|
||||
activeCues.setCues_(this.activeCues_);
|
||||
|
||||
return activeCues;
|
||||
},
|
||||
set: Function.prototype
|
||||
});
|
||||
|
||||
if (options.src) {
|
||||
tt.src = options.src;
|
||||
loadTrack(options.src, tt);
|
||||
} else {
|
||||
tt.loaded_ = true;
|
||||
}
|
||||
|
||||
if (browser.IS_IE8) {
|
||||
return tt;
|
||||
}
|
||||
}
|
||||
|
||||
TextTrack.prototype = Object.create(EventTarget.prototype);
|
||||
TextTrack.prototype.constructor = TextTrack;
|
||||
|
||||
/*
|
||||
* cuechange - One or more cues in the track have become active or stopped being active.
|
||||
*/
|
||||
TextTrack.prototype.allowedEvents_ = {
|
||||
'cuechange': 'cuechange'
|
||||
};
|
||||
|
||||
TextTrack.prototype.addCue = function(cue) {
|
||||
let tracks = this.tech_.textTracks();
|
||||
|
||||
if (tracks) {
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
if (tracks[i] !== this) {
|
||||
tracks[i].removeCue(cue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.cues_.push(cue);
|
||||
this['cues'].setCues_(this.cues_);
|
||||
};
|
||||
|
||||
TextTrack.prototype.removeCue = function(removeCue) {
|
||||
let removed = false;
|
||||
|
||||
for (let i = 0, l = this.cues_.length; i < l; i++) {
|
||||
let cue = this.cues_[i];
|
||||
if (cue === removeCue) {
|
||||
this.cues_.splice(i, 1);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
this.cues.setCues_(this.cues_);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Downloading stuff happens below this point
|
||||
*/
|
||||
var parseCues = function(srcContent, track) {
|
||||
let parser = new window.WebVTT.Parser(window, window.vttjs, window.WebVTT.StringDecoder());
|
||||
const parseCues = function(srcContent, track) {
|
||||
let parser = new window.WebVTT.Parser(window,
|
||||
window.vttjs,
|
||||
window.WebVTT.StringDecoder());
|
||||
|
||||
parser.oncue = function(cue) {
|
||||
track.addCue(cue);
|
||||
@ -256,17 +43,24 @@ var parseCues = function(srcContent, track) {
|
||||
parser.flush();
|
||||
};
|
||||
|
||||
var loadTrack = function(src, track) {
|
||||
|
||||
/**
|
||||
* load a track from a specifed url
|
||||
*
|
||||
* @param {String} src url to load track from
|
||||
* @param {Track} track track to addcues to
|
||||
*/
|
||||
const loadTrack = function(src, track) {
|
||||
let opts = {
|
||||
uri: src
|
||||
};
|
||||
|
||||
let crossOrigin = isCrossOrigin(src);
|
||||
|
||||
if (crossOrigin) {
|
||||
opts.cors = crossOrigin;
|
||||
}
|
||||
|
||||
XHR(opts, Fn.bind(this, function(err, response, responseBody){
|
||||
XHR(opts, Fn.bind(this, function(err, response, responseBody) {
|
||||
if (err) {
|
||||
return log.error(err, response);
|
||||
}
|
||||
@ -284,38 +78,245 @@ var loadTrack = function(src, track) {
|
||||
}));
|
||||
};
|
||||
|
||||
var indexOf = function(searchElement, fromIndex) {
|
||||
if (this == null) {
|
||||
throw new TypeError('"this" is null or not defined');
|
||||
}
|
||||
|
||||
let O = Object(this);
|
||||
|
||||
let len = O.length >>> 0;
|
||||
|
||||
if (len === 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let n = +fromIndex || 0;
|
||||
|
||||
if (Math.abs(n) === Infinity) {
|
||||
n = 0;
|
||||
}
|
||||
|
||||
if (n >= len) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
|
||||
|
||||
while (k < len) {
|
||||
if (k in O && O[k] === searchElement) {
|
||||
return k;
|
||||
/**
|
||||
* A single text track as defined in:
|
||||
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack
|
||||
*
|
||||
* interface TextTrack : EventTarget {
|
||||
* readonly attribute TextTrackKind kind;
|
||||
* readonly attribute DOMString label;
|
||||
* readonly attribute DOMString language;
|
||||
*
|
||||
* readonly attribute DOMString id;
|
||||
* readonly attribute DOMString inBandMetadataTrackDispatchType;
|
||||
*
|
||||
* attribute TextTrackMode mode;
|
||||
*
|
||||
* readonly attribute TextTrackCueList? cues;
|
||||
* readonly attribute TextTrackCueList? activeCues;
|
||||
*
|
||||
* void addCue(TextTrackCue cue);
|
||||
* void removeCue(TextTrackCue cue);
|
||||
*
|
||||
* attribute EventHandler oncuechange;
|
||||
* };
|
||||
*
|
||||
* @param {Object=} options Object of option names and values
|
||||
* @extends EventTarget
|
||||
* @class TextTrack
|
||||
*/
|
||||
class TextTrack extends EventTarget {
|
||||
constructor(options = {}) {
|
||||
super();
|
||||
if (!options.tech) {
|
||||
throw new Error('A tech was not provided.');
|
||||
}
|
||||
|
||||
let tt = this;
|
||||
|
||||
if (browser.IS_IE8) {
|
||||
tt = document.createElement('custom');
|
||||
|
||||
for (let prop in TextTrack.prototype) {
|
||||
if (prop !== 'constructor') {
|
||||
tt[prop] = TextTrack.prototype[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tt.tech_ = options.tech;
|
||||
|
||||
let mode = TextTrackEnum.TextTrackMode[options.mode] || 'disabled';
|
||||
let kind = TextTrackEnum.TextTrackKind[options.kind] || 'subtitles';
|
||||
let label = options.label || '';
|
||||
let language = options.language || options.srclang || '';
|
||||
let id = options.id || 'vjs_text_track_' + Guid.newGUID();
|
||||
|
||||
if (kind === 'metadata' || kind === 'chapters') {
|
||||
mode = 'hidden';
|
||||
}
|
||||
|
||||
tt.cues_ = [];
|
||||
tt.activeCues_ = [];
|
||||
|
||||
let cues = new TextTrackCueList(tt.cues_);
|
||||
let activeCues = new TextTrackCueList(tt.activeCues_);
|
||||
let changed = false;
|
||||
let timeupdateHandler = Fn.bind(tt, function() {
|
||||
this.activeCues;
|
||||
if (changed) {
|
||||
this.trigger('cuechange');
|
||||
changed = false;
|
||||
}
|
||||
});
|
||||
|
||||
if (mode !== 'disabled') {
|
||||
tt.tech_.on('timeupdate', timeupdateHandler);
|
||||
}
|
||||
|
||||
Object.defineProperty(tt, 'kind', {
|
||||
get() {
|
||||
return kind;
|
||||
},
|
||||
set() {}
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'label', {
|
||||
get() {
|
||||
return label;
|
||||
},
|
||||
set() {}
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'language', {
|
||||
get() {
|
||||
return language;
|
||||
},
|
||||
set() {}
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'id', {
|
||||
get() {
|
||||
return id;
|
||||
},
|
||||
set() {}
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'mode', {
|
||||
get() {
|
||||
return mode;
|
||||
},
|
||||
set(newMode) {
|
||||
if (!TextTrackEnum.TextTrackMode[newMode]) {
|
||||
return;
|
||||
}
|
||||
mode = newMode;
|
||||
if (mode === 'showing') {
|
||||
this.tech_.on('timeupdate', timeupdateHandler);
|
||||
}
|
||||
this.trigger('modechange');
|
||||
}
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'cues', {
|
||||
get() {
|
||||
if (!this.loaded_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return cues;
|
||||
},
|
||||
set() {}
|
||||
});
|
||||
|
||||
Object.defineProperty(tt, 'activeCues', {
|
||||
get() {
|
||||
if (!this.loaded_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// nothing to do
|
||||
if (this.cues.length === 0) {
|
||||
return activeCues;
|
||||
}
|
||||
|
||||
let ct = this.tech_.currentTime();
|
||||
let active = [];
|
||||
|
||||
for (let i = 0, l = this.cues.length; i < l; i++) {
|
||||
let cue = this.cues[i];
|
||||
|
||||
if (cue.startTime <= ct && cue.endTime >= ct) {
|
||||
active.push(cue);
|
||||
} else if (cue.startTime === cue.endTime &&
|
||||
cue.startTime <= ct &&
|
||||
cue.startTime + 0.5 >= ct) {
|
||||
active.push(cue);
|
||||
}
|
||||
}
|
||||
|
||||
changed = false;
|
||||
|
||||
if (active.length !== this.activeCues_.length) {
|
||||
changed = true;
|
||||
} else {
|
||||
for (let i = 0; i < active.length; i++) {
|
||||
if (this.activeCues_.indexOf(active[i]) === -1) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.activeCues_ = active;
|
||||
activeCues.setCues_(this.activeCues_);
|
||||
|
||||
return activeCues;
|
||||
},
|
||||
set() {}
|
||||
});
|
||||
|
||||
if (options.src) {
|
||||
tt.src = options.src;
|
||||
loadTrack(options.src, tt);
|
||||
} else {
|
||||
tt.loaded_ = true;
|
||||
}
|
||||
|
||||
if (browser.IS_IE8) {
|
||||
return tt;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
return -1;
|
||||
|
||||
/**
|
||||
* add a cue to the internal list of cues
|
||||
*
|
||||
* @param {Object} cue the cue to add to our internal list
|
||||
* @method addCue
|
||||
*/
|
||||
addCue(cue) {
|
||||
let tracks = this.tech_.textTracks();
|
||||
|
||||
if (tracks) {
|
||||
for (let i = 0; i < tracks.length; i++) {
|
||||
if (tracks[i] !== this) {
|
||||
tracks[i].removeCue(cue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.cues_.push(cue);
|
||||
this.cues.setCues_(this.cues_);
|
||||
}
|
||||
|
||||
/**
|
||||
* remvoe a cue from our internal list
|
||||
*
|
||||
* @param {Object} removeCue the cue to remove from our internal list
|
||||
* @method removeCue
|
||||
*/
|
||||
removeCue(removeCue) {
|
||||
let removed = false;
|
||||
|
||||
for (let i = 0, l = this.cues_.length; i < l; i++) {
|
||||
let cue = this.cues_[i];
|
||||
|
||||
if (cue === removeCue) {
|
||||
this.cues_.splice(i, 1);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
this.cues.setCues_(this.cues_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* cuechange - One or more cues in the track have become active or stopped being active.
|
||||
*/
|
||||
TextTrack.prototype.allowedEvents_ = {
|
||||
cuechange: 'cuechange'
|
||||
};
|
||||
|
||||
export default TextTrack;
|
||||
|
Loading…
Reference in New Issue
Block a user