mirror of
https://github.com/videojs/video.js.git
synced 2025-09-16 09:26:56 +02:00
feat: Allow techs to change poster if player option techCanOverridePoster
is set (#4921)
The option for the player techCanOverridePoster is introduced in this commit. It allows techs to update the post whenever they like. isPosterFromTech_ is introduced as a private player field in order to track when a poster was set by a tech. This allows us to clear the poster whenever the tech is disposed of by the player. Additionally, attempting to set the same poster more than once will have no effect / no changes will be made, since the poster is the same. This was done in order to stop triggering multiple posterchange events when calling player.poster(aPoster) with techCanOverridePoster set to true. When a tech is disposed and a poster was set by it, unset the poster. Pass a `canOverridePoster` option to techs to know whether techCanOverridePoster was set. Fixes #4910.
This commit is contained in:
committed by
Gary Katsevman
parent
df96a74f6b
commit
8706941573
@@ -30,6 +30,7 @@
|
||||
* [plugins](#plugins)
|
||||
* [sourceOrder](#sourceorder)
|
||||
* [sources](#sources)
|
||||
* [techCanOverridePoster](#techCanOverridePoster)
|
||||
* [techOrder](#techorder)
|
||||
* [vtt.js](#vttjs)
|
||||
* [Component Options](#component-options)
|
||||
@@ -254,6 +255,15 @@ Using `<source>` elements will have the same effect:
|
||||
</video>
|
||||
```
|
||||
|
||||
### `techCanOverridePoster`
|
||||
|
||||
> Type: `boolean`
|
||||
|
||||
Gives the possibility to techs to override the player's poster
|
||||
and integrate into the player's poster life-cycle.
|
||||
This can be useful when multiple techs are used and each has to set their own poster
|
||||
any time a new source is played.
|
||||
|
||||
### `techOrder`
|
||||
|
||||
> Type: `Array`, Default: `['html5']`
|
||||
|
@@ -57,6 +57,21 @@ videojs("videoID", {
|
||||
});
|
||||
```
|
||||
|
||||
### Posters
|
||||
|
||||
By default, techs will have to handle their own posters and are somewhat locked out of the player's poster lifecycle.
|
||||
However, when the player is initialized with the `techCanOverridePoster` option
|
||||
it will be possible for techs to integrate into that lifecycle and the player's `PosterImage` component to be used.
|
||||
|
||||
Techs can check if they have this capability by checking the `canOverridePoster` boolean in their options.
|
||||
|
||||
**`techCanOverridePoster` requirements**
|
||||
|
||||
- `poster()` which returns the tech's current poster url
|
||||
- `setPoster()` which updates the tech's poster url and triggers a `posterchange` event
|
||||
which the player will handle
|
||||
|
||||
|
||||
## Technology Ordering
|
||||
|
||||
When Video.js is given an array of sources, which to use is determined by finding the first supported source / tech combination. Each tech will be queried in the order specified in `techOrder` whether it can play the first source. The first match wins. If no tech can play the first source, then the next will be tested. It's important to set the `type` of each source correctly for this test to be accurate.
|
||||
|
@@ -317,6 +317,9 @@ class Player extends Component {
|
||||
// Run base component initializing with new options
|
||||
super(null, options, ready);
|
||||
|
||||
// Tracks when a tech changes the poster
|
||||
this.isPosterFromTech_ = false;
|
||||
|
||||
// Turn off API access because we're loading a new tech that might load asynchronously
|
||||
this.isReady_ = false;
|
||||
|
||||
@@ -513,6 +516,8 @@ class Player extends Component {
|
||||
|
||||
if (this.tech_) {
|
||||
this.tech_.dispose();
|
||||
this.isPosterFromTech_ = false;
|
||||
this.poster_ = '';
|
||||
}
|
||||
|
||||
if (this.playerElIngest_) {
|
||||
@@ -924,7 +929,8 @@ class Player extends Component {
|
||||
'poster': this.poster(),
|
||||
'language': this.language(),
|
||||
'playerElIngest': this.playerElIngest_ || false,
|
||||
'vtt.js': this.options_['vtt.js']
|
||||
'vtt.js': this.options_['vtt.js'],
|
||||
'canOverridePoster': !!this.options_.techCanOverridePoster
|
||||
};
|
||||
|
||||
TRACK_TYPES.names.forEach((name) => {
|
||||
@@ -1020,6 +1026,13 @@ class Player extends Component {
|
||||
this.tech_.dispose();
|
||||
|
||||
this.tech_ = false;
|
||||
|
||||
if (this.isPosterFromTech_) {
|
||||
this.poster_ = '';
|
||||
this.trigger('posterchange');
|
||||
}
|
||||
|
||||
this.isPosterFromTech_ = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2692,12 +2705,18 @@ class Player extends Component {
|
||||
src = '';
|
||||
}
|
||||
|
||||
if (src === this.poster_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update the internal poster variable
|
||||
this.poster_ = src;
|
||||
|
||||
// update the tech's poster
|
||||
this.techCall_('setPoster', src);
|
||||
|
||||
this.isPosterFromTech_ = false;
|
||||
|
||||
// alert components that the poster has been set
|
||||
/**
|
||||
* This event fires when the poster image is changed on the player.
|
||||
@@ -2721,11 +2740,16 @@ class Player extends Component {
|
||||
* @private
|
||||
*/
|
||||
handleTechPosterChange_() {
|
||||
if (!this.poster_ && this.tech_ && this.tech_.poster) {
|
||||
this.poster_ = this.tech_.poster() || '';
|
||||
if ((!this.poster_ || this.options_.techCanOverridePoster) && this.tech_ && this.tech_.poster) {
|
||||
const newPoster = this.tech_.poster() || '';
|
||||
|
||||
// Let components know the poster has changed
|
||||
this.trigger('posterchange');
|
||||
if (newPoster !== this.poster_) {
|
||||
this.poster_ = newPoster;
|
||||
this.isPosterFromTech_ = true;
|
||||
|
||||
// Let components know the poster has changed
|
||||
this.trigger('posterchange');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1709,3 +1709,99 @@ QUnit.test('player.duration() sets the value of player.cache_.duration', functio
|
||||
player.duration(200);
|
||||
assert.equal(player.duration(), 200, 'duration() set and get integer duration value');
|
||||
});
|
||||
|
||||
QUnit.test('setPoster in tech with `techCanOverridePoster` in player should override poster', function(assert) {
|
||||
const player = TestHelpers.makePlayer({
|
||||
techCanOverridePoster: true
|
||||
});
|
||||
const posterchangeSpy = sinon.spy();
|
||||
const firstPosterUrl = 'https://wherever.test/test.jpg';
|
||||
const techPosterUrl = 'https://somewhere.text/my/image.png';
|
||||
|
||||
assert.equal(player.options_.techCanOverridePoster, true, 'make sure player option was passed correctly');
|
||||
assert.equal(player.tech_.options_.canOverridePoster, true, 'make sure tech option was passed correctly');
|
||||
|
||||
player.on('posterchange', posterchangeSpy);
|
||||
|
||||
player.poster('');
|
||||
assert.ok(posterchangeSpy.notCalled, 'posterchangeSpy not called when no change of poster');
|
||||
assert.equal(player.isPosterFromTech_, false, "ensure tech didn't change poster after empty call from player");
|
||||
|
||||
player.poster(firstPosterUrl);
|
||||
assert.ok(posterchangeSpy.calledOnce, 'posterchangeSpy only called once on update');
|
||||
assert.equal(player.poster(), firstPosterUrl, "ensure tech didn't change poster after setting from player");
|
||||
assert.equal(player.isPosterFromTech_, false, "ensure player didn't mark poster as changed by the tech");
|
||||
|
||||
posterchangeSpy.reset();
|
||||
|
||||
player.tech_.setPoster(techPosterUrl);
|
||||
assert.ok(posterchangeSpy.calledOnce, "posterchangeSpy should've been called");
|
||||
assert.equal(player.isPosterFromTech_, true, 'ensure player marked poster as set by tech after the fact');
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
||||
QUnit.test('setPoster in tech WITHOUT `techCanOverridePoster` in player should NOT override poster', function(assert) {
|
||||
const player = TestHelpers.makePlayer();
|
||||
const posterchangeSpy = sinon.spy();
|
||||
const firstPosterUrl = 'https://wherever.test/test.jpg';
|
||||
const techPosterUrl = 'https://somewhere.test/my/image.png';
|
||||
|
||||
assert.equal(player.options_.techCanOverridePoster, undefined, "ensure player option wasn't unwittingly set");
|
||||
assert.equal(player.tech_.options_.canOverridePoster, false, "ensure tech option wasn't unwittinyly set");
|
||||
|
||||
player.on('posterchange', posterchangeSpy);
|
||||
|
||||
player.poster(firstPosterUrl);
|
||||
assert.ok(posterchangeSpy.calledOnce, 'posterchangeSpy only called once on update');
|
||||
assert.equal(player.poster(), firstPosterUrl, "ensure tech didn't change poster after setting from player");
|
||||
assert.equal(player.isPosterFromTech_, false, "ensure player didn't mark poster as changed by the tech");
|
||||
|
||||
posterchangeSpy.reset();
|
||||
|
||||
player.tech_.setPoster(techPosterUrl);
|
||||
assert.ok(posterchangeSpy.notCalled, "posterchangeSpy shouldn't have been called");
|
||||
assert.equal(player.isPosterFromTech_, false, "ensure tech didn't change poster because player option was false");
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
||||
QUnit.test('disposing a tech that set a poster, should unset the poster', function(assert) {
|
||||
const player = TestHelpers.makePlayer({
|
||||
techCanOverridePoster: true
|
||||
});
|
||||
const techPosterUrl = 'https://somewhere.test/my/image.png';
|
||||
|
||||
assert.equal(player.options_.techCanOverridePoster, true, 'make sure player option was passed correctly');
|
||||
assert.equal(player.tech_.options_.canOverridePoster, true, 'make sure tech option was passed correctly');
|
||||
|
||||
player.tech_.setPoster(techPosterUrl);
|
||||
assert.equal(player.poster(), techPosterUrl, 'player poster should equal tech poster');
|
||||
assert.equal(player.isPosterFromTech_, true, 'setting the poster with the tech should be remembered in the player');
|
||||
|
||||
player.unloadTech_();
|
||||
|
||||
assert.equal(player.poster(), '', 'ensure poster set by poster is unset after tech disposal');
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
||||
QUnit.test('disposing a tech that dit NOT set a poster, should keep the poster', function(assert) {
|
||||
const player = TestHelpers.makePlayer({
|
||||
techCanOverridePoster: true
|
||||
});
|
||||
const posterUrl = 'https://myposter.test/lol.jpg';
|
||||
|
||||
assert.equal(player.options_.techCanOverridePoster, true, 'make sure player option was passed correctly');
|
||||
assert.equal(player.tech_.options_.canOverridePoster, true, 'make sure tech option was passed correctly');
|
||||
|
||||
player.poster(posterUrl);
|
||||
assert.equal(player.poster(), posterUrl, 'player poster should NOT have changed');
|
||||
assert.equal(player.isPosterFromTech_, false, 'player should mark poster as set by itself');
|
||||
|
||||
player.unloadTech_();
|
||||
|
||||
assert.equal(player.poster(), posterUrl, 'player poster should stay the same after unloading / dispoing tech');
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
@@ -28,6 +28,7 @@ class TechFaker extends Tech {
|
||||
}
|
||||
setPoster(val) {
|
||||
this.el().poster = val;
|
||||
this.trigger('posterchange');
|
||||
}
|
||||
|
||||
setControls(val) {}
|
||||
|
Reference in New Issue
Block a user