mirror of
https://github.com/videojs/video.js.git
synced 2025-01-04 06:48:49 +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)
|
## HEAD (Unreleased)
|
||||||
* @gkatsev updated videojs badges in the README ([view](https://github.com/videojs/video.js/pull/3134))
|
* @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 * as browser from '../utils/browser.js';
|
||||||
import document from 'global/document';
|
import document from 'global/document';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* A List of text track cues as defined in:
|
||||||
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist
|
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackcuelist
|
||||||
*
|
*
|
||||||
* interface TextTrackCueList {
|
* interface TextTrackCueList {
|
||||||
@ -12,72 +13,93 @@ import document from 'global/document';
|
|||||||
* getter TextTrackCue (unsigned long index);
|
* getter TextTrackCue (unsigned long index);
|
||||||
* TextTrackCue? getCueById(DOMString id);
|
* TextTrackCue? getCueById(DOMString id);
|
||||||
* };
|
* };
|
||||||
|
*
|
||||||
|
* @param {Array} cues A list of cues to be initialized with
|
||||||
|
* @class TextTrackCueList
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function TextTrackCueList (cues) {
|
class TextTrackCueList {
|
||||||
let list = this;
|
constructor(cues) {
|
||||||
|
let list = this;
|
||||||
|
|
||||||
if (browser.IS_IE8) {
|
if (browser.IS_IE8) {
|
||||||
list = document.createElement('custom');
|
list = document.createElement('custom');
|
||||||
|
|
||||||
for (let prop in TextTrackCueList.prototype) {
|
for (let prop in TextTrackCueList.prototype) {
|
||||||
if (prop !== 'constructor') {
|
if (prop !== 'constructor') {
|
||||||
list[prop] = TextTrackCueList.prototype[prop];
|
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', {
|
for (let i = 0, l = this.length; i < l; i++) {
|
||||||
get: function() {
|
let cue = this[i];
|
||||||
return this.length_;
|
|
||||||
|
if (cue.id === id) {
|
||||||
|
result = cue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (browser.IS_IE8) {
|
return result;
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
export default TextTrackCueList;
|
||||||
|
@ -1,27 +1,39 @@
|
|||||||
/**
|
/**
|
||||||
* @file text-track-enums.js
|
* @file text-track-enums.js
|
||||||
*
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode
|
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackmode
|
||||||
*
|
*
|
||||||
* enum TextTrackMode { "disabled", "hidden", "showing" };
|
* enum TextTrackMode { "disabled", "hidden", "showing" };
|
||||||
*/
|
*/
|
||||||
var TextTrackMode = {
|
const TextTrackMode = {
|
||||||
'disabled': 'disabled',
|
disabled: 'disabled',
|
||||||
'hidden': 'hidden',
|
hidden: 'hidden',
|
||||||
'showing': 'showing'
|
showing: 'showing'
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrackkind
|
* 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 = {
|
const TextTrackKind = {
|
||||||
'subtitles': 'subtitles',
|
subtitles: 'subtitles',
|
||||||
'captions': 'captions',
|
captions: 'captions',
|
||||||
'descriptions': 'descriptions',
|
descriptions: 'descriptions',
|
||||||
'chapters': 'chapters',
|
chapters: 'chapters',
|
||||||
'metadata': 'metadata'
|
metadata: 'metadata'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* jshint ignore:start */
|
||||||
|
// we ignore jshint here because it does not see
|
||||||
|
// TextTrackMode or TextTrackKind as defined here somehow...
|
||||||
export { TextTrackMode, TextTrackKind };
|
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 * as browser from '../utils/browser.js';
|
||||||
import document from 'global/document';
|
import document from 'global/document';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* A text track list as defined in:
|
||||||
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist
|
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttracklist
|
||||||
*
|
*
|
||||||
* interface TextTrackList : EventTarget {
|
* interface TextTrackList : EventTarget {
|
||||||
@ -18,50 +19,140 @@ import document from 'global/document';
|
|||||||
* attribute EventHandler onaddtrack;
|
* attribute EventHandler onaddtrack;
|
||||||
* attribute EventHandler onremovetrack;
|
* 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) {
|
class TextTrackList extends EventTarget {
|
||||||
list = document.createElement('custom');
|
constructor(tracks = []) {
|
||||||
|
super();
|
||||||
|
let list = this;
|
||||||
|
|
||||||
for (let prop in TextTrackList.prototype) {
|
if (browser.IS_IE8) {
|
||||||
if (prop !== 'constructor') {
|
list = document.createElement('custom');
|
||||||
list[prop] = TextTrackList.prototype[prop];
|
|
||||||
|
for (let prop in TextTrackList.prototype) {
|
||||||
|
if (prop !== 'constructor') {
|
||||||
|
list[prop] = TextTrackList.prototype[prop];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tracks = tracks || [];
|
list.tracks_ = [];
|
||||||
list.tracks_ = [];
|
|
||||||
|
|
||||||
Object.defineProperty(list, 'length', {
|
Object.defineProperty(list, 'length', {
|
||||||
get: function() {
|
get() {
|
||||||
return this.tracks_.length;
|
return this.tracks_.length;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < tracks.length; i++) {
|
||||||
|
list.addTrack_(tracks[i]);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
for (let i = 0; i < tracks.length; i++) {
|
if (browser.IS_IE8) {
|
||||||
list.addTrack_(tracks[i]);
|
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.
|
* change - One or more tracks in the track list have been enabled or disabled.
|
||||||
* addtrack - A track has been added to the track list.
|
* addtrack - A track has been added to the track list.
|
||||||
* removetrack - A track has been removed from the track list.
|
* removetrack - A track has been removed from the track list.
|
||||||
*/
|
*/
|
||||||
TextTrackList.prototype.allowedEvents_ = {
|
TextTrackList.prototype.allowedEvents_ = {
|
||||||
'change': 'change',
|
change: 'change',
|
||||||
'addtrack': 'addtrack',
|
addtrack: 'addtrack',
|
||||||
'removetrack': 'removetrack'
|
removetrack: 'removetrack'
|
||||||
};
|
};
|
||||||
|
|
||||||
// emulate attribute EventHandler support to allow for feature detection
|
// 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;
|
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;
|
export default TextTrackList;
|
||||||
|
@ -13,229 +13,16 @@ import window from 'global/window';
|
|||||||
import { isCrossOrigin } from '../utils/url.js';
|
import { isCrossOrigin } from '../utils/url.js';
|
||||||
import XHR from 'xhr';
|
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 {
|
* @param {String} srcContent webVTT file contents
|
||||||
* readonly attribute TextTrackKind kind;
|
* @param {Track} track track to addcues to
|
||||||
* 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;
|
|
||||||
* };
|
|
||||||
*/
|
*/
|
||||||
function TextTrack (options={}) {
|
const parseCues = function(srcContent, track) {
|
||||||
if (!options.tech) {
|
let parser = new window.WebVTT.Parser(window,
|
||||||
throw new Error('A tech was not provided.');
|
window.vttjs,
|
||||||
}
|
window.WebVTT.StringDecoder());
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
parser.oncue = function(cue) {
|
parser.oncue = function(cue) {
|
||||||
track.addCue(cue);
|
track.addCue(cue);
|
||||||
@ -256,17 +43,24 @@ var parseCues = function(srcContent, track) {
|
|||||||
parser.flush();
|
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 = {
|
let opts = {
|
||||||
uri: src
|
uri: src
|
||||||
};
|
};
|
||||||
|
|
||||||
let crossOrigin = isCrossOrigin(src);
|
let crossOrigin = isCrossOrigin(src);
|
||||||
|
|
||||||
if (crossOrigin) {
|
if (crossOrigin) {
|
||||||
opts.cors = crossOrigin;
|
opts.cors = crossOrigin;
|
||||||
}
|
}
|
||||||
|
|
||||||
XHR(opts, Fn.bind(this, function(err, response, responseBody){
|
XHR(opts, Fn.bind(this, function(err, response, responseBody) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return log.error(err, response);
|
return log.error(err, response);
|
||||||
}
|
}
|
||||||
@ -284,38 +78,245 @@ var loadTrack = function(src, track) {
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
var indexOf = function(searchElement, fromIndex) {
|
/**
|
||||||
if (this == null) {
|
* A single text track as defined in:
|
||||||
throw new TypeError('"this" is null or not defined');
|
* https://html.spec.whatwg.org/multipage/embedded-content.html#texttrack
|
||||||
}
|
*
|
||||||
|
* interface TextTrack : EventTarget {
|
||||||
let O = Object(this);
|
* readonly attribute TextTrackKind kind;
|
||||||
|
* readonly attribute DOMString label;
|
||||||
let len = O.length >>> 0;
|
* readonly attribute DOMString language;
|
||||||
|
*
|
||||||
if (len === 0) {
|
* readonly attribute DOMString id;
|
||||||
return -1;
|
* readonly attribute DOMString inBandMetadataTrackDispatchType;
|
||||||
}
|
*
|
||||||
|
* attribute TextTrackMode mode;
|
||||||
let n = +fromIndex || 0;
|
*
|
||||||
|
* readonly attribute TextTrackCueList? cues;
|
||||||
if (Math.abs(n) === Infinity) {
|
* readonly attribute TextTrackCueList? activeCues;
|
||||||
n = 0;
|
*
|
||||||
}
|
* void addCue(TextTrackCue cue);
|
||||||
|
* void removeCue(TextTrackCue cue);
|
||||||
if (n >= len) {
|
*
|
||||||
return -1;
|
* attribute EventHandler oncuechange;
|
||||||
}
|
* };
|
||||||
|
*
|
||||||
let k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
|
* @param {Object=} options Object of option names and values
|
||||||
|
* @extends EventTarget
|
||||||
while (k < len) {
|
* @class TextTrack
|
||||||
if (k in O && O[k] === searchElement) {
|
*/
|
||||||
return k;
|
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;
|
export default TextTrack;
|
||||||
|
Loading…
Reference in New Issue
Block a user