1
0
mirror of https://github.com/videojs/video.js.git synced 2025-03-29 22:07:10 +02:00

feat: Add normalizeAutoplay option to treat autoplay: true as autoplay: "play" (#7190)

This PR adds a new option to treat autoplay: true the same as autoplay: 'play'. In general we want video.js to handle as much of the autoplay logic itself as possible, since the browser's treatment of the video element's autoplay attribute is less predictable. For now the default option value is false, but it may be made the default behavior in a future major version.
This commit is contained in:
Alex Barstow 2021-06-08 11:03:51 -04:00 committed by GitHub
parent 35ad17a0ef
commit b4ad93a10e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 6 deletions

View File

@ -31,6 +31,7 @@
* [liveTracker.trackingThreshold](#livetrackertrackingthreshold)
* [liveTracker.liveTolerance](#livetrackerlivetolerance)
* [nativeControlsForTouch](#nativecontrolsfortouch)
* [normalizeAutoplay](#normalizeautoplay)
* [notSupportedMessage](#notsupportedmessage)
* [noUITitleAttributes](#nouititleattributes)
* [fullscreen](#fullscreen)
@ -294,6 +295,12 @@ An option for the liveTracker component of the player that controls how far from
Explicitly set a default value for [the associated tech option](#nativecontrolsfortouch).
### `normalizeAutoplay`
> Type: `boolean`
Specify whether setting `autoplay: true` and `<video autoplay>` should be treated the same as `autoplay: 'play'`, i.e. the `autoplay` attribute should be removed from (or not added to) the video element and `play()` be initiated manually by Video.js rather than the browser.
### `notSupportedMessage`
> Type: `string`

View File

@ -1127,9 +1127,13 @@ class Player extends Component {
// Turn off API access because we're loading a new tech that might load asynchronously
this.isReady_ = false;
// if autoplay is a string we pass false to the tech
let autoplay = this.autoplay();
// if autoplay is a string (or `true` with normalizeAutoplay: true) we pass false to the tech
// because the player is going to handle autoplay on `loadstart`
const autoplay = typeof this.autoplay() === 'string' ? false : this.autoplay();
if (typeof this.autoplay() === 'string' || this.autoplay() === true && this.options_.normalizeAutoplay) {
autoplay = false;
}
// Grab tech-specific options from player options and add source and parent element to use.
const techOptions = {
@ -1412,7 +1416,7 @@ class Player extends Component {
// autoplay happens after loadstart for the browser,
// so we mimic that behavior
this.manualAutoplay_(this.autoplay());
this.manualAutoplay_(this.autoplay() === true && this.options_.normalizeAutoplay ? 'play' : this.autoplay());
}
/**
@ -3678,10 +3682,10 @@ class Player extends Component {
let techAutoplay;
// if the value is a valid string set it to that
if (typeof value === 'string' && (/(any|play|muted)/).test(value)) {
// if the value is a valid string set it to that, or normalize `true` to 'play', if need be
if (typeof value === 'string' && (/(any|play|muted)/).test(value) || value === true && this.options_.normalizeAutoplay) {
this.options_.autoplay = value;
this.manualAutoplay_(value);
this.manualAutoplay_(typeof value === 'string' ? value : 'play');
techAutoplay = false;
// any falsy value sets autoplay to false in the browser,
@ -5041,6 +5045,8 @@ Player.prototype.options_ = {
// Default message to show when a video cannot be played.
notSupportedMessage: 'No compatible source was found for this media.',
normalizeAutoplay: false,
fullscreen: {
options: {
navigationUI: 'hide'

View File

@ -189,6 +189,28 @@ QUnit.test('option = "play" play, no muted', function(assert) {
assert.equal(this.counts.failure, 0, 'failure count');
});
QUnit.test('option = true w/ normalizeAutoplay = true play, no muted', function(assert) {
this.createPlayer({
autoplay: true,
normalizeAutoplay: true
}, {}, this.resolvePromise);
assert.equal(this.player.autoplay(), true, 'player.autoplay getter');
assert.equal(this.player.tech_.autoplay(), false, 'tech.autoplay getter');
this.player.tech_.trigger('loadstart');
assert.equal(this.counts.play, 1, 'play count');
assert.equal(this.counts.muted, 0, 'muted count');
assert.equal(this.counts.success, 1, 'success count');
assert.equal(this.counts.failure, 0, 'failure count');
this.player.tech_.trigger('loadstart');
assert.equal(this.counts.play, 2, 'play count');
assert.equal(this.counts.muted, 0, 'muted count');
assert.equal(this.counts.success, 2, 'success count');
assert.equal(this.counts.failure, 0, 'failure count');
});
QUnit.test('option = "any" play, no muted', function(assert) {
this.createPlayer({autoplay: 'any'}, {}, this.resolvePromise);

View File

@ -322,6 +322,27 @@ QUnit.test('should get current sources from src set', function(assert) {
player.dispose();
});
QUnit.test('should remove autoplay attribute when normalizeAutoplay: true', function(assert) {
const fixture = document.getElementById('qunit-fixture');
let html = '<video id="example_1" class="video-js" autoplay preload="none">';
html += '<source src="http://google.com" type="video/mp4">';
html += '<source src="http://google.com" type="video/webm">';
html += '<track kind="captions" attrtest>';
html += '</video>';
fixture.innerHTML += html;
const tag = document.getElementById('example_1');
const player = TestHelpers.makePlayer({normalizeAutoplay: true}, tag);
player.loadTech_('Html5');
assert.equal(player.autoplay(), true, 'autoplay option is set to true');
assert.equal(tag.getAttribute('autoplay'), null, 'autoplay attribute removed');
});
QUnit.test('should asynchronously fire error events during source selection', function(assert) {
assert.expect(2);