Skip to content

Commit

Permalink
feat: Allow techs to change poster if player option `techCanOverrideP…
Browse files Browse the repository at this point in the history
…oster` 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.
  • Loading branch information
Michael Vogel authored and gkatsev committed Mar 7, 2018
1 parent df96a74 commit 8706941
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 5 deletions.
10 changes: 10 additions & 0 deletions docs/guides/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
* [plugins](#plugins)
* [sourceOrder](#sourceorder)
* [sources](#sources)
* [techCanOverridePoster](#techCanOverridePoster)
* [techOrder](#techorder)
* [vtt.js](#vttjs)
* [Component Options](#component-options)
Expand Down Expand Up @@ -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']`
Expand Down
15 changes: 15 additions & 0 deletions docs/guides/tech.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
34 changes: 29 additions & 5 deletions src/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -513,6 +516,8 @@ class Player extends Component {

if (this.tech_) {
this.tech_.dispose();
this.isPosterFromTech_ = false;
this.poster_ = '';
}

if (this.playerElIngest_) {
Expand Down Expand Up @@ -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) => {
Expand Down Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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.
Expand All @@ -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');
}
}
}

Expand Down
96 changes: 96 additions & 0 deletions test/unit/player.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
1 change: 1 addition & 0 deletions test/unit/tech/tech-faker.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class TechFaker extends Tech {
}
setPoster(val) {
this.el().poster = val;
this.trigger('posterchange');
}

setControls(val) {}
Expand Down

0 comments on commit 8706941

Please sign in to comment.