1
0
mirror of https://github.com/videojs/video.js.git synced 2024-11-28 08:58:46 +02:00

@heff updated the poster to use CSS styles to display; fixed the poster not showing if not originally set. closes #1568

This commit is contained in:
Steve Heffernan 2014-10-16 12:59:41 -07:00
parent a6019d4207
commit af02d158da
14 changed files with 210 additions and 94 deletions

View File

@ -25,6 +25,7 @@
"process",
"PlayerTest",
"TestHelpers",
"asyncTest",
"deepEqual",
"equal",

View File

@ -7,6 +7,7 @@ CHANGELOG
* @OlehTsvirko added a Ukrainian translation ([view](https://github.com/videojs/video.js/pull/1562))
* @OlehTsvirko added a Russian translation ([view](https://github.com/videojs/video.js/pull/1563))
* @thijstriemstra added a Dutch translation ([view](https://github.com/videojs/video.js/pull/1566))
* @heff updated the poster to use CSS styles to display; fixed the poster not showing if not originally set ([view](https://github.com/videojs/video.js/pull/1568))
--------------------

View File

@ -936,6 +936,22 @@ body.vjs-full-window {
width: 100%;
}
/* Hide the poster after the video has started playing */
.video-js.vjs-has-started .vjs-poster {
display: none;
}
/* Don't hide the poster if we're playing audio */
.video-js.vjs-audio.vjs-has-started .vjs-poster {
display: block;
}
/* Hide the poster when controls are disabled because it's clickable
and the native poster can take over */
.video-js.vjs-controls-disabled .vjs-poster {
display: none;
}
/* Hide the poster when native controls are used otherwise it covers them */
.video-js.vjs-using-native-controls .vjs-poster {
display: none;

View File

@ -47,8 +47,14 @@ vjs.Component = vjs.CoreObject.extend({
// Updated options with supplied options
options = this.options(options);
// Get ID from options, element, or create using player ID and unique ID
this.id_ = options['id'] || ((options['el'] && options['el']['id']) ? options['el']['id'] : player.id() + '_component_' + vjs.guid++ );
// Get ID from options or options element if one is supplied
this.id_ = options['id'] || (options['el'] && options['el']['id']);
// If there was no ID from the options, generate one
if (!this.id_) {
// Don't require the player ID function in the case of mock players
this.id_ = ((player.id && player.id()) || 'no_player') + '_component_' + vjs.guid++;
}
this.name_ = options['name'] || null;
@ -976,6 +982,11 @@ vjs.Component.prototype.emitTapEvents = function(){
vjs.Component.prototype.enableTouchActivity = function() {
var report, touchHolding, touchEnd;
// Don't continue if the root player doesn't support reporting user activity
if (!this.player().reportUserActivity) {
return;
}
// listener for reporting that the user is active
report = vjs.bind(this.player(), this.player().reportUserActivity);

View File

@ -412,6 +412,7 @@ vjs.IS_FIREFOX = (/Firefox/i).test(vjs.USER_AGENT);
vjs.IS_CHROME = (/Chrome/i).test(vjs.USER_AGENT);
vjs.TOUCH_ENABLED = !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch);
vjs.BACKGROUND_SIZE_SUPPORTED = 'backgroundSize' in vjs.TEST_VID.style;
/**
* Apply attributes to an HTML element.

View File

@ -55,9 +55,10 @@ vjs.Player = vjs.Component.extend({
this.cache_ = {};
// Set poster
this.poster_ = options['poster'];
this.poster_ = options['poster'] || '';
// Set controls
this.controls_ = options['controls'];
this.controls_ = !!options['controls'];
// Original tag settings stored in options
// now remove immediately so native controls don't flash.
// May be turned back on by HTML5 tech if nativeControlsForTouch is true
@ -1284,6 +1285,12 @@ vjs.Player.prototype.poster = function(src){
return this.poster_;
}
// The correct way to remove a poster is to set as an empty string
// other falsey values will throw errors
if (!src) {
src = '';
}
// update the internal poster variable
this.poster_ = src;

View File

@ -12,27 +12,23 @@ vjs.PosterImage = vjs.Button.extend({
init: function(player, options){
vjs.Button.call(this, player, options);
if (player.poster()) {
this.src(player.poster());
}
if (!player.poster() || !player.controls()) {
this.hide();
}
player.on('posterchange', vjs.bind(this, function(){
this.src(player.poster());
}));
if (!player.isAudio()) {
player.on('play', vjs.bind(this, this.hide));
}
this.update();
player.on('posterchange', vjs.bind(this, this.update));
}
});
// use the test el to check for backgroundSize style support
var _backgroundSizeSupported = 'backgroundSize' in vjs.TEST_VID.style;
/**
* Clean up the poster image
*/
vjs.PosterImage.prototype.dispose = function(){
this.player().off('posterchange', this.update);
vjs.Button.prototype.dispose.call(this);
};
/**
* Create the poster image element
* @return {Element}
*/
vjs.PosterImage.prototype.createEl = function(){
var el = vjs.createEl('div', {
className: 'vjs-poster',
@ -41,40 +37,63 @@ vjs.PosterImage.prototype.createEl = function(){
tabIndex: -1
});
if (!_backgroundSizeSupported) {
// setup an img element as a fallback for IE8
el.appendChild(vjs.createEl('img'));
// To ensure the poster image resizes while maintaining its original aspect
// ratio, use a div with `background-size` when available. For browsers that
// do not support `background-size` (e.g. IE8), fall back on using a regular
// img element.
if (!vjs.BACKGROUND_SIZE_SUPPORTED) {
this.fallbackImg_ = vjs.createEl('img');
el.appendChild(this.fallbackImg_);
}
return el;
};
vjs.PosterImage.prototype.src = function(url){
var el = this.el();
/**
* Event handler for updates to the player's poster source
*/
vjs.PosterImage.prototype.update = function(){
var url = this.player().poster();
// getter
// can't think of a need for a getter here
// see #838 if on is needed in the future
// still don't want a getter to set src as undefined
if (url === undefined) {
return;
}
this.setSrc(url);
// setter
// To ensure the poster image resizes while maintaining its original aspect
// ratio, use a div with `background-size` when available. For browsers that
// do not support `background-size` (e.g. IE8), fall back on using a regular
// img element.
if (_backgroundSizeSupported) {
el.style.backgroundImage = 'url("' + url + '")';
// If there's no poster source we should display:none on this component
// so it's not still clickable or right-clickable
if (url) {
// Remove the display style property that hide() adds
// as opposed to show() which sets display to block
// In the future it might be worth creating an `unhide` component method
this.el_.style.display = '';
} else {
el.firstChild.src = url;
this.hide();
}
};
vjs.PosterImage.prototype.onClick = function(){
// Only accept clicks when controls are enabled
if (this.player().controls()) {
this.player_.play();
/**
* Set the poster source depending on the display method
*/
vjs.PosterImage.prototype.setSrc = function(url){
var backgroundImage;
if (this.fallbackImg_) {
this.fallbackImg_.src = url;
} else {
backgroundImage = '';
// Any falsey values should stay as an empty string, otherwise
// this will throw an extra error
if (url) {
backgroundImage = 'url("' + url + '")';
}
this.el_.style.backgroundImage = backgroundImage;
}
};
/**
* Event handler for clicks on the poster image
*/
vjs.PosterImage.prototype.onClick = function(){
// We don't want a click to trigger playback when controls are disabled
// but CSS should be hiding the poster to prevent that from happening
this.player_.play();
};

View File

@ -3,6 +3,9 @@
<head>
<title>Video.js Test Suite</title>
<!-- Video.js CSS -->
<link rel="stylesheet" href="../build/files/video-js.css" type="text/css">
<!-- Sinon -->
<script src="../node_modules/sinon/pkg/sinon.js"></script>
<script src="../node_modules/sinon/pkg/sinon-ie.js"></script>
@ -11,9 +14,6 @@
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css" />
<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
<!-- Video.js CSS -->
<link rel="stylesheet" href="../build/files/video-js.css" type="text/css">
<script type="text/javascript">
(function(){

View File

@ -59,6 +59,7 @@ module.exports = function(config) {
customLaunchers: customLaunchers,
files: [
'../build/files/video-js.css',
'../test/karma-qunit-shim.js',
"../src/js/core.js",
"../src/js/core-object.js",

View File

@ -7,6 +7,7 @@ module.exports = function(config) {
singleRun: true,
files: [
'../build/files/video-js.min.css',
'../test/karma-qunit-shim.js',
'../node_modules/sinon/pkg/sinon.js',
'../build/files/minified.video.js',

View File

@ -7,6 +7,7 @@ module.exports = function(config) {
singleRun: true,
files: [
'../build/files/video-js.min.css',
'../test/karma-qunit-shim.js',
'../node_modules/sinon/pkg/sinon.js',
'../build/files/test.minified.video.js'

View File

@ -3,6 +3,9 @@
<head>
<title>Video.js Test Suite</title>
<!-- Video.js CSS -->
<link rel="stylesheet" href="../build/files/video-js.css" type="text/css">
<!-- Sinon -->
<script src="../node_modules/sinon/pkg/sinon.js"></script>
<script src="../node_modules/sinon/pkg/sinon-ie.js"></script>
@ -11,9 +14,6 @@
<link rel="stylesheet" href="../node_modules/qunitjs/qunit/qunit.css" />
<script src="../node_modules/qunitjs/qunit/qunit.js"></script>
<!-- Video.js CSS -->
<link rel="stylesheet" href="../build/files/video-js.css" type="text/css">
<!-- SOURCE COMPILED WITH TESTS
grunt-contrib-qunit doesn't support query vars, so making this script
so we can automatically run compiled tests too.

View File

@ -1,49 +1,91 @@
module('PosterImage');
module('PosterImage', {
'setup': function(){
// Store the original background support so we can test different vals
this.origVal = vjs.BACKGROUND_SIZE_SUPPORTED;
this.poster1 = 'http://example.com/poster.jpg';
this.poster2 = 'http://example.com/UPDATED.jpg';
test('should update the poster source', function(){
var player, posterImage, posterEl, poster1, poster2;
poster1 = 'http://example.com/poster.jpg';
poster2 = 'http://example.com/UPDATED.jpg';
player = PlayerTest.makePlayer({ poster: poster1 });
posterImage = new vjs.PosterImage(player);
posterEl = posterImage.el();
// check alternative methods for displaying the poster
function checkPosterSource(src) {
var modern, oldIE;
// in modern browsers we use backgroundImage to display the poster
modern = posterEl.style.backgroundImage.toString().indexOf(src) !== -1;
// otherwise we create an image elemement
oldIE = posterEl.firstChild && posterEl.firstChild.src === src;
if (modern || oldIE) {
return true;
}
return false;
// Create a mock player object that responds as a player would
this.mockPlayer = {
poster_: this.poster1,
poster: function(){
return this.poster_;
},
handler_: null,
on: function(type, handler){
this.handler_ = handler;
},
trigger: function(type){
this.handler_.call();
}
};
},
'teardown': function(){
vjs.BACKGROUND_SIZE_SUPPORTED = this.origVal;
}
ok(checkPosterSource(poster1), 'displays the correct poster');
posterImage.src(poster2);
ok(checkPosterSource(poster2), 'displays the correct poster after updating');
posterImage.src();
ok(checkPosterSource(poster2), 'doesnt change poster when attempting a get');
player.dispose();
});
test('should not hide the poster if audio track is used', function() {
var audio = document.createElement('audio'),
poster = 'http://example.com/poster.jpg',
player = PlayerTest.makePlayer({ 'poster': poster, 'controls': true }, audio),
posterImage = new vjs.PosterImage(player),
posterEl = posterImage.el();
test('should create and update a poster image', function(){
var posterImage;
player.trigger('play');
equal(posterEl.style.display, '', 'poster image is not hidden when audio track is used');
vjs.BACKGROUND_SIZE_SUPPORTED = true;
posterImage = new vjs.PosterImage(this.mockPlayer);
equal(posterImage.el().style.backgroundImage, 'url('+this.poster1+')', 'Background image used');
// Update with a new poster source and check the new value
this.mockPlayer.poster_ = this.poster2;
this.mockPlayer.trigger('posterchange');
equal(posterImage.el().style.backgroundImage, 'url('+this.poster2+')', 'Background image updated');
});
test('should create and update a fallback image in older browsers', function(){
var posterImage;
vjs.BACKGROUND_SIZE_SUPPORTED = false;
posterImage = new vjs.PosterImage(this.mockPlayer);
equal(posterImage.fallbackImg_.src, this.poster1, 'Fallback image created');
// Update with a new poster source and check the new value
this.mockPlayer.poster_ = this.poster2;
this.mockPlayer.trigger('posterchange');
equal(posterImage.fallbackImg_.src, this.poster2, 'Fallback image updated');
});
test('should remove itself from the document flow when there is no poster', function(){
var posterImage;
posterImage = new vjs.PosterImage(this.mockPlayer);
equal(posterImage.el().style.display, '', 'Poster image shows by default');
// Update with an empty string
this.mockPlayer.poster_ = '';
this.mockPlayer.trigger('posterchange');
equal(posterImage.el().style.display, 'none', 'Poster image hides with an empty source');
// Updated with a valid source
this.mockPlayer.poster_ = this.poster2;
this.mockPlayer.trigger('posterchange');
equal(posterImage.el().style.display, '', 'Poster image shows again when there is a source');
});
test('should hide the poster in the appropriate player states', function(){
var posterImage = new vjs.PosterImage(this.mockPlayer);
var playerDiv = document.createElement('div');
var fixture = document.getElementById('qunit-fixture');
var el = posterImage.el();
// Remove the source so when we add to the DOM it doesn't throw an error
// We want to poster to still think it has a real source so it doesn't hide itself
posterImage.setSrc('');
// Add the elements to the DOM so styles are computed
playerDiv.appendChild(el);
fixture.appendChild(playerDiv);
playerDiv.className = 'video-js vjs-has-started';
equal(TestHelpers.getComputedStyle(el, 'display'), 'none', 'The poster hides when the video has started');
playerDiv.className = 'video-js vjs-has-started vjs-audio';
equal(TestHelpers.getComputedStyle(el, 'display'), 'block', 'The poster continues to show when playing audio');
});

View File

@ -19,3 +19,18 @@ var PlayerTest = {
return player = new videojs.Player(videoTag, playerOptions);
}
};
var TestHelpers = {
getComputedStyle: function(el, rule){
var val;
if(window.getComputedStyle){
val = window.getComputedStyle(el, null).getPropertyValue(rule);
// IE8
} else if(el.currentStyle){
val = el.currentStyle[rule];
}
return val;
}
};