mirror of
https://github.com/videojs/video.js.git
synced 2025-02-02 11:34:50 +02:00
feat(player): Add playbackRates() method (#7228)
Adds a new playbackRates() method that takes an Array of numbers representing the rates that are wanted to show up in the playback rates menu. When new rates are given, a playbackrateschange event will trigger, which will be used by the PlaybackRatesMenuButton to update itself. An empty array will hide the menu. No value will return the currently set playback rates. Other values will be ignored. Fixes #7198
This commit is contained in:
parent
39de502f72
commit
6259ef79e9
@ -2,7 +2,6 @@
|
||||
* @file playback-rate-menu-button.js
|
||||
*/
|
||||
import MenuButton from '../../menu/menu-button.js';
|
||||
import Menu from '../../menu/menu.js';
|
||||
import PlaybackRateMenuItem from './playback-rate-menu-item.js';
|
||||
import Component from '../../component.js';
|
||||
import * as Dom from '../../utils/dom.js';
|
||||
@ -33,6 +32,7 @@ class PlaybackRateMenuButton extends MenuButton {
|
||||
|
||||
this.on(player, 'loadstart', (e) => this.updateVisibility(e));
|
||||
this.on(player, 'ratechange', (e) => this.updateLabel(e));
|
||||
this.on(player, 'playbackrateschange', (e) => this.handlePlaybackRateschange(e));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,22 +78,18 @@ class PlaybackRateMenuButton extends MenuButton {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the playback rate menu
|
||||
* Create the list of menu items. Specific to each subclass.
|
||||
*
|
||||
* @return {Menu}
|
||||
* Menu object populated with {@link PlaybackRateMenuItem}s
|
||||
*/
|
||||
createMenu() {
|
||||
const menu = new Menu(this.player());
|
||||
createItems() {
|
||||
const rates = this.playbackRates();
|
||||
const items = [];
|
||||
|
||||
if (rates) {
|
||||
for (let i = rates.length - 1; i >= 0; i--) {
|
||||
menu.addChild(new PlaybackRateMenuItem(this.player(), {rate: rates[i] + 'x'}));
|
||||
}
|
||||
for (let i = rates.length - 1; i >= 0; i--) {
|
||||
items.push(new PlaybackRateMenuItem(this.player(), {rate: rates[i] + 'x'}));
|
||||
}
|
||||
|
||||
return menu;
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,6 +128,15 @@ class PlaybackRateMenuButton extends MenuButton {
|
||||
this.player().playbackRate(newRate);
|
||||
}
|
||||
|
||||
/**
|
||||
* On playbackrateschange, update the menu to account for the new items.
|
||||
*
|
||||
* @listens Player#playbackrateschange
|
||||
*/
|
||||
handlePlaybackRateschange(event) {
|
||||
this.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get possible playback rates
|
||||
*
|
||||
@ -139,7 +144,7 @@ class PlaybackRateMenuButton extends MenuButton {
|
||||
* All possible playback rates
|
||||
*/
|
||||
playbackRates() {
|
||||
return this.options_.playbackRates || (this.options_.playerOptions && this.options_.playerOptions.playbackRates);
|
||||
return this.player().playbackRates() || [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,7 +26,7 @@ class PlaybackRateMenuItem extends MenuItem {
|
||||
|
||||
// Modify options for parent MenuItem class's init.
|
||||
options.label = label;
|
||||
options.selected = rate === 1;
|
||||
options.selected = rate === player.playbackRate();
|
||||
options.selectable = true;
|
||||
options.multiSelectable = false;
|
||||
|
||||
|
@ -508,6 +508,8 @@ class Player extends Component {
|
||||
|
||||
this.middleware_ = [];
|
||||
|
||||
this.playbackRates(options.playbackRates);
|
||||
|
||||
this.initChildren();
|
||||
|
||||
// Set isAudio based on whether or not an audio tag was used
|
||||
@ -2218,6 +2220,7 @@ class Player extends Component {
|
||||
src: '',
|
||||
source: {},
|
||||
sources: [],
|
||||
playbackRates: [],
|
||||
volume: 1
|
||||
};
|
||||
}
|
||||
@ -4858,6 +4861,45 @@ class Player extends Component {
|
||||
this.previousLogLevel_ = undefined;
|
||||
this.debugEnabled_ = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or get current playback rates.
|
||||
* Takes an array and updates the playback rates menu with the new items.
|
||||
* Pass in an empty array to hide the menu.
|
||||
* Values other than arrays are ignored.
|
||||
*
|
||||
* @fires Player#playbackrateschange
|
||||
* @param {number[]} newRates
|
||||
* The new rates that the playback rates menu should update to.
|
||||
* An empty array will hide the menu
|
||||
* @return {number[]} When used as a getter will return the current playback rates
|
||||
*/
|
||||
playbackRates(newRates) {
|
||||
if (newRates === undefined) {
|
||||
return this.cache_.playbackRates;
|
||||
}
|
||||
|
||||
// ignore any value that isn't an array
|
||||
if (!Array.isArray(newRates)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore any arrays that don't only contain numbers
|
||||
if (!newRates.every((rate) => typeof rate === 'number')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.cache_.playbackRates = newRates;
|
||||
|
||||
/**
|
||||
* fires when the playback rates in a player are changed
|
||||
*
|
||||
* @event Player#playbackrateschange
|
||||
* @type {EventTarget~Event}
|
||||
*/
|
||||
this.trigger('playbackrateschange');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,13 +141,49 @@ QUnit.test('calculateDistance should use changedTouches, if available', function
|
||||
slider.dispose();
|
||||
});
|
||||
|
||||
QUnit.test('should hide playback rate control if it\'s not supported', function(assert) {
|
||||
QUnit.test('playback rate button is hidden by default', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const player = TestHelpers.makePlayer();
|
||||
const playbackRate = new PlaybackRateMenuButton(player);
|
||||
|
||||
assert.ok(playbackRate.el().className.indexOf('vjs-hidden') >= 0, 'playbackRate is not hidden');
|
||||
assert.ok(playbackRate.el().className.indexOf('vjs-hidden') >= 0, 'playbackRate is hidden');
|
||||
|
||||
player.dispose();
|
||||
playbackRate.dispose();
|
||||
});
|
||||
|
||||
QUnit.test('playback rate button is not hidden if playback rates are set', function(assert) {
|
||||
assert.expect(1);
|
||||
|
||||
const player = TestHelpers.makePlayer({
|
||||
playbackRates: [1, 2, 3]
|
||||
});
|
||||
const playbackRate = new PlaybackRateMenuButton(player);
|
||||
|
||||
assert.ok(playbackRate.el().className.indexOf('vjs-hidden') === -1, 'playbackRate is not hidden');
|
||||
|
||||
player.dispose();
|
||||
playbackRate.dispose();
|
||||
});
|
||||
|
||||
QUnit.test('should show or hide playback rate menu button on playback rates change', function(assert) {
|
||||
const rates = [1, 2, 3];
|
||||
const norates = [];
|
||||
let playbackRatesReturnValue = rates;
|
||||
const player = TestHelpers.makePlayer();
|
||||
|
||||
player.playbackRates = () => playbackRatesReturnValue;
|
||||
|
||||
const playbackRate = new PlaybackRateMenuButton(player);
|
||||
|
||||
assert.ok(playbackRate.el().className.indexOf('vjs-hidden') === -1, 'playbackRate is not hidden');
|
||||
|
||||
playbackRatesReturnValue = norates;
|
||||
|
||||
player.trigger('playbackrateschange');
|
||||
|
||||
assert.ok(playbackRate.el().className.indexOf('vjs-hidden') >= 0, 'playbackRate is hidden');
|
||||
|
||||
player.dispose();
|
||||
playbackRate.dispose();
|
||||
|
@ -1809,6 +1809,7 @@ QUnit.test('player#reset clears the player cache', function(assert) {
|
||||
player.src(sources);
|
||||
player.duration(10);
|
||||
player.playbackRate(0.5);
|
||||
player.playbackRates([1, 2, 3]);
|
||||
player.volume(0.2);
|
||||
|
||||
assert.strictEqual(player.currentSrc(), sources[0].src, 'currentSrc is correct');
|
||||
@ -1816,6 +1817,7 @@ QUnit.test('player#reset clears the player cache', function(assert) {
|
||||
assert.deepEqual(player.currentSources(), sources, 'currentSources is correct');
|
||||
assert.strictEqual(player.duration(), 10, 'duration is correct');
|
||||
assert.strictEqual(player.playbackRate(), 0.5, 'playbackRate is correct');
|
||||
assert.deepEqual(player.playbackRates(), [1, 2, 3], 'playbackRates is correct');
|
||||
assert.strictEqual(player.volume(), 0.2, 'volume is correct');
|
||||
assert.strictEqual(player.lastVolume_(), 0.2, 'lastVolume_ is correct');
|
||||
|
||||
@ -1832,6 +1834,7 @@ QUnit.test('player#reset clears the player cache', function(assert) {
|
||||
assert.strictEqual(player.getCache().currentTime, 0, 'currentTime is correct');
|
||||
assert.ok(isNaN(player.duration()), 'duration is correct');
|
||||
assert.strictEqual(player.playbackRate(), 1, 'playbackRate is correct');
|
||||
assert.deepEqual(player.playbackRates(), [], 'playbackRates is correct');
|
||||
assert.strictEqual(player.volume(), 1, 'volume is correct');
|
||||
assert.strictEqual(player.lastVolume_(), 1, 'lastVolume_ is correct');
|
||||
});
|
||||
@ -2599,3 +2602,51 @@ QUnit[testOrSkip]('Should only allow requestPictureInPicture if the tech support
|
||||
player.requestPictureInPicture();
|
||||
assert.equal(count, 1, 'requestPictureInPicture not passed through when tech does not support');
|
||||
});
|
||||
|
||||
QUnit.test('playbackRates should trigger a playbackrateschange event', function(assert) {
|
||||
const player = TestHelpers.makePlayer({});
|
||||
const rates = [];
|
||||
let rateschangeCount = 0;
|
||||
|
||||
player.on('playbackrateschange', function() {
|
||||
rates.push(player.playbackRates());
|
||||
rateschangeCount++;
|
||||
});
|
||||
|
||||
player.playbackRates([1, 2, 3]);
|
||||
player.playbackRates([]);
|
||||
player.playbackRates([1, 4]);
|
||||
|
||||
assert.equal(rateschangeCount, 3, 'we got 3 playbackrateschange events');
|
||||
assert.deepEqual(rates[0], [1, 2, 3], 'first rates is 1,2,3');
|
||||
assert.deepEqual(rates[1], [], 'second rates is empty');
|
||||
assert.deepEqual(rates[2], [1, 4], 'third rates is 1,4');
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
||||
QUnit.test('playbackRates only accepts arrays of numbers', function(assert) {
|
||||
const player = TestHelpers.makePlayer();
|
||||
let rateschangeCount = 0;
|
||||
|
||||
player.on('playbackrateschange', function() {
|
||||
rateschangeCount++;
|
||||
});
|
||||
|
||||
player.playbackRates([1, 2, 3]);
|
||||
assert.equal(rateschangeCount, 1, 'we got a playbackrateschange event');
|
||||
|
||||
player.playbackRates('hello');
|
||||
assert.equal(rateschangeCount, 1, 'we did not get a playbackrateschange event');
|
||||
|
||||
player.playbackRates([1, 4]);
|
||||
assert.equal(rateschangeCount, 2, 'we got a playbackrateschange event');
|
||||
|
||||
player.playbackRates(5);
|
||||
assert.equal(rateschangeCount, 2, 'we did not get a playbackrateschange event');
|
||||
|
||||
player.playbackRates(['hello', '2', 'why?']);
|
||||
assert.equal(rateschangeCount, 2, 'we did not get a playbackrateschange event');
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user