mirror of
https://github.com/videojs/video.js.git
synced 2025-01-27 11:22:06 +02:00
Close GH-672: Control bar updates. Fixes #556, Fixes #500, Fixes #374, Fixes #403, Fixes #441, Fixes #193, Fixes #602, Fixes #561, Fixes #281
This commit is contained in:
parent
699c476575
commit
02de927043
@ -4,20 +4,21 @@ Version GENERATED_AT_BUILD
|
||||
Create your own skin at http://designer.videojs.com
|
||||
*/
|
||||
|
||||
// To customize the player skin, change the values of the variables or edit the
|
||||
// To customize the player skin, change the values of the variables or edit the
|
||||
// CSS below.
|
||||
// (This file uses LESS. Learn more at http://lesscss.org/)
|
||||
|
||||
// The base font size controls the size of everything, not just text. All
|
||||
// The base font size controls the size of everything, not just text. All
|
||||
// diminensions use em-based sizes so that the scale along with the font size.
|
||||
// Try increasing it to 20px and see what happens.
|
||||
@base-font-size: 10px;
|
||||
@touch-device-font-size: 15px;
|
||||
|
||||
// The main font color controls the color of the text and the icons (font icons)
|
||||
@main-font-color: #CCCCCC; // e.g. rgb(255, 255, 255) or #ffffff
|
||||
|
||||
// The default color of control backgrounds is mostly black but with a little
|
||||
// bit of blue so it can still be seen on all black video frames, which are
|
||||
// The default color of control backgrounds is mostly black but with a little
|
||||
// bit of blue so it can still be seen on all black video frames, which are
|
||||
// common.
|
||||
@control-bg-color: #07141E; // e.g. rgb(255, 255, 255) or #ffffff
|
||||
@control-bg-alpha: 0.7; // 1.0 = 100% opacity, 0.0 = 0% opacity
|
||||
@ -32,12 +33,12 @@ Create your own skin at http://designer.videojs.com
|
||||
@slider-background-color: #333333;
|
||||
@slider-background-alpha: 0.9; // 1.0 = 100% opacity, 0.0 = 0% opacity
|
||||
|
||||
// The "Big Play Button" is the play button that shows before the video plays.
|
||||
// To center it set the align values to center and middle. The typical location
|
||||
// The "Big Play Button" is the play button that shows before the video plays.
|
||||
// To center it set the align values to center and middle. The typical location
|
||||
// of the button is the center, but there is trend towards moving it to a corner
|
||||
// where it gets out of the way of valuable content in the poster image.
|
||||
@big-play-align: left; // left, center, or right
|
||||
@big-play-vertical-align: top; // top, middle, or bottom
|
||||
@big-play-vertical-align: top; // top, middle, or bottom
|
||||
// The button colors match the control colors by default but you can customize
|
||||
// them by replace the variables (@control-bg-color) with your own color values.
|
||||
@big-play-bg-color: @control-bg-color;
|
||||
@ -58,9 +59,9 @@ Create your own skin at http://designer.videojs.com
|
||||
|
||||
/* SKIN
|
||||
================================================================================
|
||||
The main class name for all skin-specific styles. To make your own skin,
|
||||
replace all occurances of 'vjs-default-skin' with a new name. Then add your new
|
||||
skin name to your video tag instead of the default skin.
|
||||
The main class name for all skin-specific styles. To make your own skin,
|
||||
replace all occurances of 'vjs-default-skin' with a new name. Then add your new
|
||||
skin name to your video tag instead of the default skin.
|
||||
e.g. <video class="video-js my-skin-name">
|
||||
*/
|
||||
.vjs-default-skin {
|
||||
@ -98,7 +99,7 @@ The control icons are from a custom font. Each icon corresponds to a character
|
||||
@captions-icon: "\e008";
|
||||
|
||||
/* Base UI Component Classes
|
||||
--------------------------------------------------------------------------------
|
||||
--------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Slider - used for Volume bar and Seek bar */
|
||||
@ -141,13 +142,13 @@ The control icons are from a custom font. Each icon corresponds to a character
|
||||
|
||||
/* Control Bar
|
||||
--------------------------------------------------------------------------------
|
||||
The default control bar that is a container for most of the controls.
|
||||
The default control bar that is a container for most of the controls.
|
||||
*/
|
||||
.vjs-default-skin .vjs-control-bar {
|
||||
/* Start hidden *///
|
||||
display: none;
|
||||
position: absolute;
|
||||
/* Place control bar at the bottom of the player box/video.
|
||||
/* Place control bar at the bottom of the player box/video.
|
||||
If you want more margin below the control bar, add more height. *///
|
||||
bottom: 0;
|
||||
/* Use left/right to stretch to 100% width of player div *///
|
||||
@ -159,6 +160,36 @@ The default control bar that is a container for most of the controls.
|
||||
.background-color-with-alpha(@control-bg-color, @control-bg-alpha);
|
||||
}
|
||||
|
||||
/* Show the control bar only once the video has started playing */
|
||||
.vjs-default-skin.vjs-has-started .vjs-control-bar {
|
||||
display: block;
|
||||
/* Visibility needed to make sure things hide in older browsers too. */
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
|
||||
@trans: visibility 0.1s, opacity 0.1s; // Var needed because of comma
|
||||
.transition(@trans);
|
||||
}
|
||||
|
||||
/* Hide the control bar when the video is playing and the user is inactive */
|
||||
.vjs-default-skin.vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
|
||||
@trans: visibility 1.0s, opacity 1.0s;
|
||||
.transition(@trans);
|
||||
}
|
||||
|
||||
.vjs-default-skin.vjs-controls-disabled .vjs-control-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vjs-default-skin.vjs-using-native-controls .vjs-control-bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
/* General styles for individual controls. *///
|
||||
.vjs-default-skin .vjs-control {
|
||||
outline: none;
|
||||
@ -191,15 +222,15 @@ The default control bar that is a container for most of the controls.
|
||||
text-shadow: 0em 0em 1em rgba(255, 255, 255, 1);
|
||||
}
|
||||
|
||||
.vjs-default-skin .vjs-control:focus {
|
||||
.vjs-default-skin .vjs-control:focus {
|
||||
/* outline: 0; *///
|
||||
/* keyboard-only users cannot see the focus on several of the UI elements when
|
||||
this is set to 0 */
|
||||
}
|
||||
|
||||
/* Hide control text visually, but have it available for screenreaders */
|
||||
.vjs-default-skin .vjs-control-text {
|
||||
.hide-visually;
|
||||
.vjs-default-skin .vjs-control-text {
|
||||
.hide-visually;
|
||||
}
|
||||
|
||||
/* Play/Pause
|
||||
@ -388,7 +419,7 @@ The default control bar that is a container for most of the controls.
|
||||
|
||||
/* Big Play Button (play button at start)
|
||||
--------------------------------------------------------------------------------
|
||||
Positioning of the play button in the center or other corners can be done more
|
||||
Positioning of the play button in the center or other corners can be done more
|
||||
easily in the skin designer. http://designer.videojs.com/
|
||||
*/
|
||||
.vjs-default-skin .vjs-big-play-button {
|
||||
@ -420,6 +451,20 @@ easily in the skin designer. http://designer.videojs.com/
|
||||
.transition(all 0.4s);
|
||||
}
|
||||
|
||||
/* Hide if controls are disabled */
|
||||
.vjs-default-skin.vjs-controls-disabled .vjs-big-play-button {
|
||||
display: none;
|
||||
}
|
||||
/* Hide when video starts playing */
|
||||
.vjs-default-skin.vjs-has-started .vjs-big-play-button {
|
||||
display: none;
|
||||
}
|
||||
/* Hide on mobile devices. Remove when we stop using native controls
|
||||
by default on mobile */
|
||||
.vjs-default-skin.vjs-using-native-controls .vjs-big-play-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vjs-default-skin:hover .vjs-big-play-button,
|
||||
.vjs-default-skin .vjs-big-play-button:focus {
|
||||
outline: 0;
|
||||
@ -609,18 +654,18 @@ REQUIRED STYLES (be careful overriding)
|
||||
================================================================================
|
||||
When loading the player, the video tag is replaced with a DIV,
|
||||
that will hold the video tag or object tag for other playback methods.
|
||||
The div contains the video playback element (Flash or HTML5) and controls,
|
||||
The div contains the video playback element (Flash or HTML5) and controls,
|
||||
and sets the width and height of the video.
|
||||
|
||||
** If you want to add some kind of border/padding (e.g. a frame), or special
|
||||
positioning, use another containing element. Otherwise you risk messing up
|
||||
** If you want to add some kind of border/padding (e.g. a frame), or special
|
||||
positioning, use another containing element. Otherwise you risk messing up
|
||||
control positioning and full window mode. **
|
||||
*/
|
||||
.video-js {
|
||||
background-color: #000;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
/* Start with 10px for base font size so other dimensions can be em based and
|
||||
/* Start with 10px for base font size so other dimensions can be em based and
|
||||
easily calculable. */
|
||||
font-size: @base-font-size;
|
||||
/* Allow poster to be vertially aligned. */
|
||||
@ -649,7 +694,7 @@ control positioning and full window mode. **
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when
|
||||
/* Fix for Firefox 9 fullscreen (only if it is enabled). Not needed when
|
||||
checking fullScreenEnabled. */
|
||||
.video-js:-moz-full-screen { position: absolute; }
|
||||
|
||||
@ -675,9 +720,12 @@ body.vjs-full-window {
|
||||
_position: absolute;
|
||||
}
|
||||
.video-js:-webkit-full-screen {
|
||||
width: 100% !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
.video-js.vjs-fullscreen.vjs-user-inactive {
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
/* Poster Styles */
|
||||
.vjs-poster {
|
||||
@ -699,6 +747,11 @@ body.vjs-full-window {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Hide the poster when native controls are used otherwise it covers them */
|
||||
.video-js.vjs-using-native-controls .vjs-poster {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Text Track Styles */
|
||||
/* Overall track holder for both captions and subtitles */
|
||||
.video-js .vjs-text-track-display {
|
||||
@ -722,26 +775,6 @@ body.vjs-full-window {
|
||||
.video-js .vjs-captions { color: #fc6 /* Captions are yellow */; }
|
||||
.vjs-tt-cue { display: block; }
|
||||
|
||||
/* Fading sytles, used to fade control bar. */
|
||||
.vjs-fade-in {
|
||||
display: block !important;
|
||||
/* Visibility needed to make sure things hide in older browsers too. */
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
|
||||
@trans: visibility 0.1s, opacity 0.1s; // Var needed because of comma
|
||||
.transition(@trans);
|
||||
}
|
||||
.vjs-fade-out {
|
||||
display: block !important;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
|
||||
@trans: visibility 1.5s, opacity 1.5s;
|
||||
.transition(@trans);
|
||||
/* Wait a moment before fading out the control bar */
|
||||
.transition-delay(2s);
|
||||
}
|
||||
/* Hide disabled or unsupported controls */
|
||||
.vjs-default-skin .vjs-hidden { display: none; }
|
||||
|
||||
@ -751,9 +784,9 @@ body.vjs-full-window {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
// MIXINS
|
||||
// MIXINS
|
||||
// =============================================================================
|
||||
// Mixins are a LESS feature and are used to add vendor prefixes to CSS rules
|
||||
// Mixins are a LESS feature and are used to add vendor prefixes to CSS rules
|
||||
// when needed.
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/box-shadow
|
||||
@ -813,7 +846,7 @@ body.vjs-full-window {
|
||||
.user-select (@string: none) {
|
||||
/* user-select *///
|
||||
-webkit-user-select: @string;
|
||||
-moz-user-select: @string;
|
||||
-moz-user-select: @string;
|
||||
-ms-user-select: @string;
|
||||
user-select: @string;
|
||||
}
|
||||
@ -822,14 +855,14 @@ body.vjs-full-window {
|
||||
// http://h5bp.com/v
|
||||
.hide-visually () {
|
||||
/* hide-visually *///
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position:
|
||||
absolute;
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position:
|
||||
absolute;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
@ -882,27 +915,27 @@ body.vjs-full-window {
|
||||
// * We want this file to continue to be accessible by people who don't know
|
||||
// LESS but know CSS. This means finding the balance between using the most
|
||||
// valuable LESS features (e.g. variables) and keeping it looking like CSS.
|
||||
// So it's best to avoid advanced LESS features like conditional statements.
|
||||
// (we're using one for the big play button position because that's a hot
|
||||
// So it's best to avoid advanced LESS features like conditional statements.
|
||||
// (we're using one for the big play button position because that's a hot
|
||||
// topic)
|
||||
//
|
||||
//
|
||||
// * We care about the readability of the CSS output of LESS, which means we
|
||||
// have to be careful about what features of LESS we use. (if you're building
|
||||
// your own skin this may not apply)
|
||||
// 1. Comments inside of rules (strangely) have an extra line added after
|
||||
// them in the CSS output. To avoid this we can add a LESS comment after
|
||||
// 1. Comments inside of rules (strangely) have an extra line added after
|
||||
// them in the CSS output. To avoid this we can add a LESS comment after
|
||||
// the CSS comment.
|
||||
// /* comment *///
|
||||
//
|
||||
//
|
||||
// 2. In a rule with nested rules, any comments outside of a rule are moved
|
||||
// to the top of the parent rule. i.e. it might look like:
|
||||
// /* title of rule 1 */
|
||||
// /* title of rule 2 */
|
||||
// .rule1 {}
|
||||
// .rule2 {}
|
||||
// This is why we aren't using nested rules inside of the
|
||||
// This is why we aren't using nested rules inside of the
|
||||
// vjs-default-skin class.
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
The original source of this file lives at
|
||||
/* -----------------------------------------------------------------------------
|
||||
The original source of this file lives at
|
||||
https://github.com/videojs/video.js/blob/master/src/css/video-js.less */
|
||||
|
@ -1,24 +1,13 @@
|
||||
/* Big Play Button
|
||||
================================================================================ */
|
||||
/**
|
||||
* Initial play button. Shows before the video has played.
|
||||
* Initial play button. Shows before the video has played. The hiding of the
|
||||
* big play button is done via CSS and player states.
|
||||
* @param {vjs.Player|Object} player
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
vjs.BigPlayButton = vjs.Button.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
vjs.Button.call(this, player, options);
|
||||
|
||||
if (!player.controls()) {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
player.on('play', vjs.bind(this, this.hide));
|
||||
// player.on('ended', vjs.bind(this, this.show));
|
||||
}
|
||||
});
|
||||
vjs.BigPlayButton = vjs.Button.extend();
|
||||
|
||||
vjs.BigPlayButton.prototype.createEl = function(){
|
||||
return vjs.Button.prototype.createEl.call(this, 'div', {
|
||||
@ -29,10 +18,5 @@ vjs.BigPlayButton.prototype.createEl = function(){
|
||||
};
|
||||
|
||||
vjs.BigPlayButton.prototype.onClick = function(){
|
||||
// Go back to the beginning if big play button is showing at the end.
|
||||
// Have to check for current time otherwise it might throw a 'not ready' error.
|
||||
//if(this.player_.currentTime()) {
|
||||
//this.player_.currentTime(0);
|
||||
//}
|
||||
this.player_.play();
|
||||
};
|
||||
|
@ -12,7 +12,9 @@ vjs.Button = vjs.Component.extend({
|
||||
vjs.Component.call(this, player, options);
|
||||
|
||||
var touchstart = false;
|
||||
this.on('touchstart', function() {
|
||||
this.on('touchstart', function(event) {
|
||||
// Stop click and other mouse events from triggering also
|
||||
event.preventDefault();
|
||||
touchstart = true;
|
||||
});
|
||||
this.on('touchmove', function() {
|
||||
@ -24,7 +26,6 @@ vjs.Button = vjs.Component.extend({
|
||||
self.onClick(event);
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
this.on('click', this.onClick);
|
||||
|
@ -539,26 +539,6 @@ vjs.Component.prototype.hide = function(){
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fade a component in using CSS
|
||||
* @return {vjs.Component}
|
||||
*/
|
||||
vjs.Component.prototype.fadeIn = function(){
|
||||
this.removeClass('vjs-fade-out');
|
||||
this.addClass('vjs-fade-in');
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fade a component out using CSS
|
||||
* @return {vjs.Component}
|
||||
*/
|
||||
vjs.Component.prototype.fadeOut = function(){
|
||||
this.removeClass('vjs-fade-in');
|
||||
this.addClass('vjs-fade-out');
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Lock an item in its visible state. To be used with fadeIn/fadeOut.
|
||||
* @return {vjs.Component}
|
||||
@ -583,15 +563,8 @@ vjs.Component.prototype.unlockShowing = function(){
|
||||
vjs.Component.prototype.disable = function(){
|
||||
this.hide();
|
||||
this.show = function(){};
|
||||
this.fadeIn = function(){};
|
||||
};
|
||||
|
||||
// TODO: Get enable working
|
||||
// vjs.Component.prototype.enable = function(){
|
||||
// this.fadeIn = vjs.Component.prototype.fadeIn;
|
||||
// this.show = vjs.Component.prototype.show;
|
||||
// };
|
||||
|
||||
/**
|
||||
* If a value is provided it will change the width of the player to that value
|
||||
* otherwise the width is returned
|
||||
@ -693,3 +666,50 @@ vjs.Component.prototype.dimension = function(widthOrHeight, num, skipListeners){
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Emit 'tap' events when touch events are supported. We're requireing them to
|
||||
* be enabled because otherwise every component would have this extra overhead
|
||||
* unnecessarily, on mobile devices where extra overhead is especially bad.
|
||||
*
|
||||
* This is being implemented so we can support taps on the video element
|
||||
* toggling the controls.
|
||||
*/
|
||||
vjs.Component.prototype.emitTapEvents = function(){
|
||||
var touchStart, touchTime, couldBeTap, noTap;
|
||||
|
||||
// Track the start time so we can determine how long the touch lasted
|
||||
touchStart = 0;
|
||||
|
||||
this.on('touchstart', function(event) {
|
||||
// Record start time so we can detect a tap vs. "touch and hold"
|
||||
touchStart = new Date().getTime();
|
||||
// Reset couldBeTap tracking
|
||||
couldBeTap = true;
|
||||
});
|
||||
|
||||
noTap = function(){
|
||||
couldBeTap = false;
|
||||
};
|
||||
// TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s
|
||||
this.on('touchmove', noTap);
|
||||
this.on('touchleave', noTap);
|
||||
this.on('touchcancel', noTap);
|
||||
|
||||
// When the touch ends, measure how long it took and trigger the appropriate
|
||||
// event
|
||||
this.on('touchend', function() {
|
||||
// Proceed only if the touchmove/leave/cancel event didn't happen
|
||||
if (couldBeTap === true) {
|
||||
// Measure how long the touch lasted
|
||||
touchTime = new Date().getTime() - touchStart;
|
||||
// The touch needs to be quick in order to consider it a tap
|
||||
if (touchTime < 250) {
|
||||
this.trigger('tap');
|
||||
// It may be good to copy the touchend event object and change the
|
||||
// type to tap, if the other event properties aren't exact after
|
||||
// vjs.fixEvent runs (e.g. event.target)
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -4,55 +4,7 @@
|
||||
* @param {Object=} options
|
||||
* @constructor
|
||||
*/
|
||||
vjs.ControlBar = vjs.Component.extend({
|
||||
/** @constructor */
|
||||
init: function(player, options){
|
||||
vjs.Component.call(this, player, options);
|
||||
|
||||
if (!player.controls()) {
|
||||
this.disable();
|
||||
}
|
||||
|
||||
player.one('play', vjs.bind(this, function(){
|
||||
var touchstart,
|
||||
fadeIn = vjs.bind(this, this.fadeIn),
|
||||
fadeOut = vjs.bind(this, this.fadeOut);
|
||||
|
||||
this.fadeIn();
|
||||
|
||||
if ( !('ontouchstart' in window) ) {
|
||||
this.player_.on('mouseover', fadeIn);
|
||||
this.player_.on('mouseout', fadeOut);
|
||||
this.player_.on('pause', vjs.bind(this, this.lockShowing));
|
||||
this.player_.on('play', vjs.bind(this, this.unlockShowing));
|
||||
}
|
||||
|
||||
touchstart = false;
|
||||
this.player_.on('touchstart', function() {
|
||||
touchstart = true;
|
||||
});
|
||||
this.player_.on('touchmove', function() {
|
||||
touchstart = false;
|
||||
});
|
||||
this.player_.on('touchend', vjs.bind(this, function(event) {
|
||||
var idx;
|
||||
if (touchstart) {
|
||||
idx = this.el().className.search('fade-in');
|
||||
if (idx !== -1) {
|
||||
this.fadeOut();
|
||||
} else {
|
||||
this.fadeIn();
|
||||
}
|
||||
}
|
||||
touchstart = false;
|
||||
|
||||
if (!this.player_.paused()) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}));
|
||||
}));
|
||||
}
|
||||
});
|
||||
vjs.ControlBar = vjs.Component.extend();
|
||||
|
||||
vjs.ControlBar.prototype.options_ = {
|
||||
loadEvent: 'play',
|
||||
@ -75,13 +27,3 @@ vjs.ControlBar.prototype.createEl = function(){
|
||||
className: 'vjs-control-bar'
|
||||
});
|
||||
};
|
||||
|
||||
vjs.ControlBar.prototype.fadeIn = function(){
|
||||
vjs.Component.prototype.fadeIn.call(this);
|
||||
this.player_.trigger('controlsvisible');
|
||||
};
|
||||
|
||||
vjs.ControlBar.prototype.fadeOut = function(){
|
||||
vjs.Component.prototype.fadeOut.call(this);
|
||||
this.player_.trigger('controlshidden');
|
||||
};
|
@ -55,14 +55,13 @@ goog.exportProperty(vjs.Component.prototype, 'width', vjs.Component.prototype.wi
|
||||
goog.exportProperty(vjs.Component.prototype, 'height', vjs.Component.prototype.height);
|
||||
goog.exportProperty(vjs.Component.prototype, 'dimensions', vjs.Component.prototype.dimensions);
|
||||
goog.exportProperty(vjs.Component.prototype, 'ready', vjs.Component.prototype.ready);
|
||||
goog.exportProperty(vjs.Component.prototype, 'fadeIn', vjs.Component.prototype.fadeIn);
|
||||
goog.exportProperty(vjs.Component.prototype, 'fadeOut', vjs.Component.prototype.fadeOut);
|
||||
|
||||
goog.exportSymbol('videojs.Player', vjs.Player);
|
||||
goog.exportProperty(vjs.Player.prototype, 'dispose', vjs.Player.prototype.dispose);
|
||||
goog.exportProperty(vjs.Player.prototype, 'requestFullScreen', vjs.Player.prototype.requestFullScreen);
|
||||
goog.exportProperty(vjs.Player.prototype, 'cancelFullScreen', vjs.Player.prototype.cancelFullScreen);
|
||||
goog.exportProperty(vjs.Player.prototype, 'bufferedPercent', vjs.Player.prototype.bufferedPercent);
|
||||
goog.exportProperty(vjs.Player.prototype, 'usingNativeControls', vjs.Player.prototype.usingNativeControls);
|
||||
|
||||
goog.exportSymbol('videojs.MediaLoader', vjs.MediaLoader);
|
||||
goog.exportSymbol('videojs.TextTrackDisplay', vjs.TextTrackDisplay);
|
||||
|
@ -343,6 +343,7 @@ vjs.IS_OLD_ANDROID = vjs.IS_ANDROID && (/webkit/i).test(vjs.USER_AGENT) && vjs.A
|
||||
vjs.IS_FIREFOX = (/Firefox/i).test(vjs.USER_AGENT);
|
||||
vjs.IS_CHROME = (/Chrome/i).test(vjs.USER_AGENT);
|
||||
|
||||
vjs.TOUCH_ENABLED = ('ontouchstart' in window);
|
||||
|
||||
/**
|
||||
* Get an element's attribute values, as defined on the HTML tag
|
||||
|
@ -182,9 +182,6 @@ vjs.Flash = vjs.MediaTechController.extend({
|
||||
// Update reference to playback technology element
|
||||
tech.el_ = el;
|
||||
|
||||
// Now that the element is ready, make a click on the swf play the video
|
||||
vjs.on(el, 'click', tech.bind(tech.onClick));
|
||||
|
||||
// Make sure swf is actually ready. Sometimes the API isn't actually yet.
|
||||
vjs.Flash.checkReady(tech);
|
||||
});
|
||||
@ -328,9 +325,6 @@ vjs.Flash['onReady'] = function(currSwf){
|
||||
// Update reference to playback technology element
|
||||
tech.el_ = el;
|
||||
|
||||
// Now that the element is ready, make a click on the swf play the video
|
||||
tech.on('click', tech.onClick);
|
||||
|
||||
vjs.Flash.checkReady(tech);
|
||||
};
|
||||
|
||||
|
@ -35,6 +35,14 @@ vjs.Html5 = vjs.MediaTechController.extend({
|
||||
this.el_.src = source.src;
|
||||
}
|
||||
|
||||
// Determine if native controls should be used
|
||||
// Our goal should be to get the custom controls on mobile solid everywhere
|
||||
// so we can remove this all together. Right now this will block custom
|
||||
// controls on touch enabled laptops like the Chrome Pixel
|
||||
if (vjs.TOUCH_ENABLED && player.options()['nativeControlsForTouch'] !== false) {
|
||||
this.useNativeControls();
|
||||
}
|
||||
|
||||
// Chrome and Safari both have issues with autoplay.
|
||||
// In Safari (5.1.1), when we move the video element into the container div, autoplay doesn't work.
|
||||
// In Chrome (15), if you have autoplay + a poster + no controls, the video gets hidden (but audio plays)
|
||||
@ -46,10 +54,7 @@ vjs.Html5 = vjs.MediaTechController.extend({
|
||||
}
|
||||
});
|
||||
|
||||
this.on('click', this.onClick);
|
||||
|
||||
this.setupTriggers();
|
||||
|
||||
this.triggerReady();
|
||||
}
|
||||
});
|
||||
@ -116,6 +121,37 @@ vjs.Html5.prototype.eventHandler = function(e){
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
vjs.Html5.prototype.useNativeControls = function(){
|
||||
var tech, player, controlsOn, controlsOff, cleanUp;
|
||||
|
||||
tech = this;
|
||||
player = this.player();
|
||||
|
||||
// If the player controls are enabled turn on the native controls
|
||||
tech.setControls(player.controls());
|
||||
|
||||
// Update the native controls when player controls state is updated
|
||||
controlsOn = function(){
|
||||
tech.setControls(true);
|
||||
};
|
||||
controlsOff = function(){
|
||||
tech.setControls(false);
|
||||
};
|
||||
player.on('controlsenabled', controlsOn);
|
||||
player.on('controlsdisabled', controlsOff);
|
||||
|
||||
// Clean up when not using native controls anymore
|
||||
cleanUp = function(){
|
||||
player.off('controlsenabled', controlsOn);
|
||||
player.off('controlsdisabled', controlsOff);
|
||||
};
|
||||
tech.on('dispose', cleanUp);
|
||||
player.on('usingcustomcontrols', cleanUp);
|
||||
|
||||
// Update the state of the player to using native controls
|
||||
player.usingNativeControls(true);
|
||||
};
|
||||
|
||||
|
||||
vjs.Html5.prototype.play = function(){ this.el_.play(); };
|
||||
vjs.Html5.prototype.pause = function(){ this.el_.pause(); };
|
||||
@ -179,29 +215,19 @@ vjs.Html5.prototype.currentSrc = function(){ return this.el_.currentSrc; };
|
||||
|
||||
vjs.Html5.prototype.preload = function(){ return this.el_.preload; };
|
||||
vjs.Html5.prototype.setPreload = function(val){ this.el_.preload = val; };
|
||||
|
||||
vjs.Html5.prototype.autoplay = function(){ return this.el_.autoplay; };
|
||||
vjs.Html5.prototype.setAutoplay = function(val){ this.el_.autoplay = val; };
|
||||
|
||||
vjs.Html5.prototype.controls = function(){ return this.el_.controls; }
|
||||
vjs.Html5.prototype.setControls = function(val){ this.el_.controls = !!val; }
|
||||
|
||||
vjs.Html5.prototype.loop = function(){ return this.el_.loop; };
|
||||
vjs.Html5.prototype.setLoop = function(val){ this.el_.loop = val; };
|
||||
|
||||
vjs.Html5.prototype.error = function(){ return this.el_.error; };
|
||||
// networkState: function(){ return this.el_.networkState; },
|
||||
// readyState: function(){ return this.el_.readyState; },
|
||||
vjs.Html5.prototype.seeking = function(){ return this.el_.seeking; };
|
||||
// initialTime: function(){ return this.el_.initialTime; },
|
||||
// startOffsetTime: function(){ return this.el_.startOffsetTime; },
|
||||
// played: function(){ return this.el_.played; },
|
||||
// seekable: function(){ return this.el_.seekable; },
|
||||
vjs.Html5.prototype.ended = function(){ return this.el_.ended; };
|
||||
// videoTracks: function(){ return this.el_.videoTracks; },
|
||||
// audioTracks: function(){ return this.el_.audioTracks; },
|
||||
// videoWidth: function(){ return this.el_.videoWidth; },
|
||||
// videoHeight: function(){ return this.el_.videoHeight; },
|
||||
// textTracks: function(){ return this.el_.textTracks; },
|
||||
// defaultPlaybackRate: function(){ return this.el_.defaultPlaybackRate; },
|
||||
// playbackRate: function(){ return this.el_.playbackRate; },
|
||||
// mediaGroup: function(){ return this.el_.mediaGroup; },
|
||||
// controller: function(){ return this.el_.controller; },
|
||||
vjs.Html5.prototype.defaultMuted = function(){ return this.el_.defaultMuted; };
|
||||
|
||||
/* HTML5 Support Testing ---------------------------------------------------- */
|
||||
|
@ -1,5 +1,6 @@
|
||||
/**
|
||||
* @fileoverview Media Technology Controller - Base class for media playback technology controllers like Flash and HTML5
|
||||
* @fileoverview Media Technology Controller - Base class for media playback
|
||||
* technology controllers like Flash and HTML5
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -13,37 +14,144 @@ vjs.MediaTechController = vjs.Component.extend({
|
||||
init: function(player, options, ready){
|
||||
vjs.Component.call(this, player, options, ready);
|
||||
|
||||
// Make playback element clickable
|
||||
// this.addEvent('click', this.proxy(this.onClick));
|
||||
|
||||
// player.triggerEvent('techready');
|
||||
this.initControlsListeners();
|
||||
}
|
||||
});
|
||||
|
||||
// destroy: function(){},
|
||||
// createElement: function(){},
|
||||
/**
|
||||
* Set up click and touch listeners for the playback element
|
||||
* On desktops, a click on the video itself will toggle playback,
|
||||
* on a mobile device a click on the video toggles controls.
|
||||
* (toggling controls is done by toggling the user state between active and
|
||||
* inactive)
|
||||
*
|
||||
* A tap can signal that a user has become active, or has become inactive
|
||||
* e.g. a quick tap on an iPhone movie should reveal the controls. Another
|
||||
* quick tap should hide them again (signaling the user is in an inactive
|
||||
* viewing state)
|
||||
*
|
||||
* In addition to this, we still want the user to be considered inactive after
|
||||
* a few seconds of inactivity.
|
||||
*
|
||||
* Note: the only part of iOS interaction we can't mimic with this setup
|
||||
* is a touch and hold on the video element counting as activity in order to
|
||||
* keep the controls showing, but that shouldn't be an issue. A touch and hold on
|
||||
* any controls will still keep the user active
|
||||
*/
|
||||
vjs.MediaTechController.prototype.initControlsListeners = function(){
|
||||
var player, tech, activateControls, deactivateControls;
|
||||
|
||||
tech = this;
|
||||
player = this.player();
|
||||
|
||||
var activateControls = function(){
|
||||
if (player.controls() && !player.usingNativeControls()) {
|
||||
tech.addControlsListeners();
|
||||
}
|
||||
};
|
||||
|
||||
deactivateControls = vjs.bind(tech, tech.removeControlsListeners);
|
||||
|
||||
// Set up event listeners once the tech is ready and has an element to apply
|
||||
// listeners to
|
||||
this.ready(activateControls);
|
||||
player.on('controlsenabled', activateControls);
|
||||
player.on('controlsdisabled', deactivateControls);
|
||||
};
|
||||
|
||||
vjs.MediaTechController.prototype.addControlsListeners = function(){
|
||||
var preventBubble, userWasActive;
|
||||
|
||||
// Some browsers (Chrome & IE) don't trigger a click on a flash swf, but do
|
||||
// trigger mousedown/up.
|
||||
// http://stackoverflow.com/questions/1444562/javascript-onclick-event-over-flash-object
|
||||
// Any touch events are set to block the mousedown event from happening
|
||||
this.on('mousedown', this.onClick);
|
||||
|
||||
// We need to block touch events on the video element from bubbling up,
|
||||
// otherwise they'll signal activity prematurely. The specific use case is
|
||||
// when the video is playing and the controls have faded out. In this case
|
||||
// only a tap (fast touch) should toggle the user active state and turn the
|
||||
// controls back on. A touch and move or touch and hold should not trigger
|
||||
// the controls (per iOS as an example at least)
|
||||
//
|
||||
// We always want to stop propagation on touchstart because touchstart
|
||||
// at the player level starts the touchInProgress interval. We can still
|
||||
// report activity on the other events, but won't let them bubble for
|
||||
// consistency. We don't want to bubble a touchend without a touchstart.
|
||||
this.on('touchstart', function(event) {
|
||||
// Stop the mouse events from also happening
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
// Record if the user was active now so we don't have to keep polling it
|
||||
userWasActive = this.player_.userActive();
|
||||
});
|
||||
|
||||
preventBubble = function(event){
|
||||
event.stopPropagation();
|
||||
if (userWasActive) {
|
||||
this.player_.reportUserActivity();
|
||||
}
|
||||
};
|
||||
|
||||
// Treat all touch events the same for consistency
|
||||
this.on('touchmove', preventBubble);
|
||||
this.on('touchleave', preventBubble);
|
||||
this.on('touchcancel', preventBubble);
|
||||
this.on('touchend', preventBubble);
|
||||
|
||||
// Turn on component tap events
|
||||
this.emitTapEvents();
|
||||
|
||||
// The tap listener needs to come after the touchend listener because the tap
|
||||
// listener cancels out any reportedUserActivity when setting userActive(false)
|
||||
this.on('tap', this.onTap);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a click on the media element. By default will play the media.
|
||||
*
|
||||
* On android browsers, having this toggle play state interferes with being
|
||||
* able to toggle the controls and toggling play state with the play button
|
||||
* Remove the listeners used for click and tap controls. This is needed for
|
||||
* toggling to controls disabled, where a tap/touch should do nothing.
|
||||
*/
|
||||
vjs.MediaTechController.prototype.onClick = (function(){
|
||||
if (vjs.IS_ANDROID) {
|
||||
return function () {};
|
||||
} else {
|
||||
return function () {
|
||||
if (this.player_.controls()) {
|
||||
if (this.player_.paused()) {
|
||||
this.player_.play();
|
||||
} else {
|
||||
this.player_.pause();
|
||||
}
|
||||
}
|
||||
};
|
||||
vjs.MediaTechController.prototype.removeControlsListeners = function(){
|
||||
// We don't want to just use `this.off()` because there might be other needed
|
||||
// listeners added by techs that extend this.
|
||||
this.off('tap');
|
||||
this.off('touchstart');
|
||||
this.off('touchmove');
|
||||
this.off('touchleave');
|
||||
this.off('touchcancel');
|
||||
this.off('touchend');
|
||||
this.off('click');
|
||||
this.off('mousedown');
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a click on the media element. By default will play/pause the media.
|
||||
*/
|
||||
vjs.MediaTechController.prototype.onClick = function(event){
|
||||
// We're using mousedown to detect clicks thanks to Flash, but mousedown
|
||||
// will also be triggered with right-clicks, so we need to prevent that
|
||||
if (event.button !== 0) return;
|
||||
|
||||
// When controls are disabled a click should not toggle playback because
|
||||
// the click is considered a control
|
||||
if (this.player().controls()) {
|
||||
if (this.player().paused()) {
|
||||
this.player().play();
|
||||
} else {
|
||||
this.player().pause();
|
||||
}
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle a tap on the media element. By default it will toggle the user
|
||||
* activity state, which hides and shows the controls.
|
||||
*/
|
||||
|
||||
vjs.MediaTechController.prototype.onTap = function(){
|
||||
this.player().userActive(!this.player().userActive());
|
||||
};
|
||||
|
||||
vjs.MediaTechController.prototype.features = {
|
||||
volumeControl: true,
|
||||
|
212
src/js/player.js
212
src/js/player.js
@ -24,22 +24,30 @@ vjs.Player = vjs.Component.extend({
|
||||
this.poster_ = options['poster'];
|
||||
// Set controls
|
||||
this.controls_ = options['controls'];
|
||||
// Use native controls for iOS and Android by default
|
||||
// until controls are more stable on those devices.
|
||||
if (options['customControlsOnMobile'] !== true && (vjs.IS_IOS || vjs.IS_ANDROID)) {
|
||||
tag.controls = options['controls'];
|
||||
this.controls_ = false;
|
||||
} else {
|
||||
// Original tag settings stored in options
|
||||
// now remove immediately so native controls don't flash.
|
||||
tag.controls = false;
|
||||
}
|
||||
// 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
|
||||
tag.controls = false;
|
||||
|
||||
// Run base component initializing with new options.
|
||||
// Builds the element through createEl()
|
||||
// Inits and embeds any child components in opts
|
||||
vjs.Component.call(this, this, options, ready);
|
||||
|
||||
// Update controls className. Can't do this when the controls are initially
|
||||
// set because the element doesn't exist yet.
|
||||
if (this.controls()) {
|
||||
this.addClass('vjs-controls-enabled');
|
||||
} else {
|
||||
this.addClass('vjs-controls-disabled');
|
||||
}
|
||||
|
||||
// TODO: Make this smarter. Toggle user state between touching/mousing
|
||||
// using events, since devices can have both touch and mouse events.
|
||||
// if (vjs.TOUCH_ENABLED) {
|
||||
// this.addClass('vjs-touch-enabled');
|
||||
// }
|
||||
|
||||
// Firstplay event implimentation. Not sold on the event yet.
|
||||
// Could probably just check currentTime==0?
|
||||
this.one('play', function(e){
|
||||
@ -71,6 +79,8 @@ vjs.Player = vjs.Component.extend({
|
||||
this[key](val);
|
||||
}, this);
|
||||
}
|
||||
|
||||
this.listenForUserActivity();
|
||||
}
|
||||
});
|
||||
|
||||
@ -377,6 +387,8 @@ vjs.Player.prototype.onFirstPlay = function(){
|
||||
if(this.options_['starttime']){
|
||||
this.currentTime(this.options_['starttime']);
|
||||
}
|
||||
|
||||
this.addClass('vjs-has-started');
|
||||
};
|
||||
|
||||
vjs.Player.prototype.onPause = function(){
|
||||
@ -848,20 +860,188 @@ vjs.Player.prototype.controls_;
|
||||
* @param {Boolean} controls Set controls to showing or not
|
||||
* @return {Boolean} Controls are showing
|
||||
*/
|
||||
vjs.Player.prototype.controls = function(controls){
|
||||
if (controls !== undefined) {
|
||||
vjs.Player.prototype.controls = function(bool){
|
||||
if (bool !== undefined) {
|
||||
bool = !!bool; // force boolean
|
||||
// Don't trigger a change event unless it actually changed
|
||||
if (this.controls_ !== controls) {
|
||||
this.controls_ = !!controls; // force boolean
|
||||
this.trigger('controlschange');
|
||||
if (this.controls_ !== bool) {
|
||||
this.controls_ = bool;
|
||||
if (bool) {
|
||||
this.removeClass('vjs-controls-disabled');
|
||||
this.addClass('vjs-controls-enabled');
|
||||
this.trigger('controlsenabled');
|
||||
} else {
|
||||
this.removeClass('vjs-controls-enabled');
|
||||
this.addClass('vjs-controls-disabled');
|
||||
this.trigger('controlsdisabled');
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
return this.controls_;
|
||||
};
|
||||
|
||||
vjs.Player.prototype.usingNativeControls_;
|
||||
|
||||
/**
|
||||
* Toggle native controls on/off. Native controls are the controls built into
|
||||
* devices (e.g. default iPhone controls), Flash, or other techs
|
||||
* (e.g. Vimeo Controls)
|
||||
*
|
||||
* **This should only be set by the current tech, because only the tech knows
|
||||
* if it can support native controls**
|
||||
*
|
||||
* @param {Boolean} bool True signals that native controls are on
|
||||
* @return {vjs.Player} Returns the player
|
||||
*/
|
||||
vjs.Player.prototype.usingNativeControls = function(bool){
|
||||
if (bool !== undefined) {
|
||||
bool = !!bool; // force boolean
|
||||
// Don't trigger a change event unless it actually changed
|
||||
if (this.usingNativeControls_ !== bool) {
|
||||
this.usingNativeControls_ = bool;
|
||||
if (bool) {
|
||||
this.addClass('vjs-using-native-controls');
|
||||
this.trigger('usingnativecontrols');
|
||||
} else {
|
||||
this.removeClass('vjs-using-native-controls');
|
||||
this.trigger('usingcustomcontrols');
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
return this.usingNativeControls_;
|
||||
};
|
||||
|
||||
vjs.Player.prototype.error = function(){ return this.techGet('error'); };
|
||||
vjs.Player.prototype.ended = function(){ return this.techGet('ended'); };
|
||||
|
||||
// When the player is first initialized, trigger activity so components
|
||||
// like the control bar show themselves if needed
|
||||
vjs.Player.prototype.userActivity_ = true;
|
||||
vjs.Player.prototype.reportUserActivity = function(event){
|
||||
this.userActivity_ = true;
|
||||
};
|
||||
|
||||
vjs.Player.prototype.userActive_ = true;
|
||||
vjs.Player.prototype.userActive = function(bool){
|
||||
if (bool !== undefined) {
|
||||
bool = !!bool;
|
||||
if (bool !== this.userActive_) {
|
||||
this.userActive_ = bool;
|
||||
if (bool) {
|
||||
// If the user was inactive and is now active we want to reset the
|
||||
// inactivity timer
|
||||
this.userActivity_ = true;
|
||||
this.removeClass('vjs-user-inactive');
|
||||
this.addClass('vjs-user-active');
|
||||
this.trigger('useractive');
|
||||
} else {
|
||||
// We're switching the state to inactive manually, so erase any other
|
||||
// activity
|
||||
this.userActivity_ = false;
|
||||
|
||||
// Chrome/Safari/IE have bugs where when you change the cursor it can
|
||||
// trigger a mousemove event. This causes an issue when you're hiding
|
||||
// the cursor when the user is inactive, and a mousemove signals user
|
||||
// activity. Making it impossible to go into inactive mode. Specifically
|
||||
// this happens in fullscreen when we really need to hide the cursor.
|
||||
//
|
||||
// When this gets resolved in ALL browsers it can be removed
|
||||
// https://code.google.com/p/chromium/issues/detail?id=103041
|
||||
this.tech.one('mousemove', function(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
this.removeClass('vjs-user-active');
|
||||
this.addClass('vjs-user-inactive');
|
||||
this.trigger('userinactive');
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
return this.userActive_;
|
||||
};
|
||||
|
||||
vjs.Player.prototype.listenForUserActivity = function(){
|
||||
var onMouseActivity, onMouseDown, mouseInProgress, onMouseUp,
|
||||
activityCheck, inactivityTimeout;
|
||||
|
||||
onMouseActivity = this.reportUserActivity;
|
||||
|
||||
onMouseDown = function() {
|
||||
onMouseActivity();
|
||||
// For as long as the they are touching the device or have their mouse down,
|
||||
// we consider them active even if they're not moving their finger or mouse.
|
||||
// So we want to continue to update that they are active
|
||||
clearInterval(mouseInProgress);
|
||||
// Setting userActivity=true now and setting the interval to the same time
|
||||
// as the activityCheck interval (250) should ensure we never miss the
|
||||
// next activityCheck
|
||||
mouseInProgress = setInterval(vjs.bind(this, onMouseActivity), 250);
|
||||
};
|
||||
|
||||
onMouseUp = function(event) {
|
||||
onMouseActivity();
|
||||
// Stop the interval that maintains activity if the mouse/touch is down
|
||||
clearInterval(mouseInProgress);
|
||||
};
|
||||
|
||||
// Any mouse movement will be considered user activity
|
||||
this.on('mousedown', onMouseDown);
|
||||
this.on('mousemove', onMouseActivity);
|
||||
this.on('mouseup', onMouseUp);
|
||||
|
||||
// Listen for keyboard navigation
|
||||
// Shouldn't need to use inProgress interval because of key repeat
|
||||
this.on('keydown', onMouseActivity);
|
||||
this.on('keyup', onMouseActivity);
|
||||
|
||||
// Consider any touch events that bubble up to be activity
|
||||
// Certain touches on the tech will be blocked from bubbling because they
|
||||
// toggle controls
|
||||
this.on('touchstart', onMouseDown);
|
||||
this.on('touchmove', onMouseActivity);
|
||||
this.on('touchend', onMouseUp);
|
||||
this.on('touchcancel', onMouseUp);
|
||||
|
||||
// Run an interval every 250 milliseconds instead of stuffing everything into
|
||||
// the mousemove/touchmove function itself, to prevent performance degradation.
|
||||
// `this.reportUserActivity` simply sets this.userActivity_ to true, which
|
||||
// then gets picked up by this loop
|
||||
// http://ejohn.org/blog/learning-from-twitter/
|
||||
activityCheck = setInterval(vjs.bind(this, function() {
|
||||
// Check to see if mouse/touch activity has happened
|
||||
if (this.userActivity_) {
|
||||
// Reset the activity tracker
|
||||
this.userActivity_ = false;
|
||||
|
||||
// If the user state was inactive, set the state to active
|
||||
this.userActive(true);
|
||||
|
||||
// Clear any existing inactivity timeout to start the timer over
|
||||
clearTimeout(inactivityTimeout);
|
||||
|
||||
// In X seconds, if no more activity has occurred the user will be
|
||||
// considered inactive
|
||||
inactivityTimeout = setTimeout(vjs.bind(this, function() {
|
||||
// Protect against the case where the inactivityTimeout can trigger just
|
||||
// before the next user activity is picked up by the activityCheck loop
|
||||
// causing a flicker
|
||||
if (!this.userActivity_) {
|
||||
this.userActive(false);
|
||||
}
|
||||
}), 2000);
|
||||
}
|
||||
}), 250);
|
||||
|
||||
// Clean up the intervals when we kill the player
|
||||
this.on('dispose', function(){
|
||||
clearInterval(activityCheck);
|
||||
clearTimeout(inactivityTimeout);
|
||||
});
|
||||
};
|
||||
|
||||
// Methods to add support for
|
||||
// networkState: function(){ return this.techCall('networkState'); },
|
||||
// readyState: function(){ return this.techCall('readyState'); },
|
||||
@ -929,3 +1109,5 @@ vjs.Player.prototype.ended = function(){ return this.techGet('ended'); };
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
|
||||
|
@ -40,5 +40,8 @@ vjs.PosterImage.prototype.createEl = function(){
|
||||
};
|
||||
|
||||
vjs.PosterImage.prototype.onClick = function(){
|
||||
this.player_.play();
|
||||
// Only accept clicks when controls are enabled
|
||||
if (this.player().controls()) {
|
||||
this.player_.play();
|
||||
}
|
||||
};
|
||||
|
@ -25,6 +25,7 @@ test('should be able to access expected player API methods', function() {
|
||||
ok(player.one, 'one exists');
|
||||
ok(player.bufferedPercent, 'bufferedPercent exists');
|
||||
ok(player.dimensions, 'dimensions exists');
|
||||
ok(player.usingNativeControls, 'usingNativeControls exists');
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
@ -66,7 +67,7 @@ test('videojs.players should be availble after minification', function() {
|
||||
fixture.appendChild(videoTag);
|
||||
|
||||
var player = videojs(id);
|
||||
equal(videojs.players[id], player, 'videojs.players is available');
|
||||
ok(videojs.players[id] === player, 'videojs.players is available');
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
@ -221,3 +221,29 @@ test('should use a defined content el for appending children', function(){
|
||||
ok(comp.el().childNodes[0]['id'] === 'contentEl', 'Content El should still exist');
|
||||
ok(comp.el().childNodes[0].childNodes[0] !== child.el(), 'Child el should be removed.');
|
||||
});
|
||||
|
||||
test('should emit a tap event', function(){
|
||||
expect(1);
|
||||
|
||||
// Fake touch support. Real touch support isn't needed for this test.
|
||||
var origTouch = vjs.TOUCH_ENABLED;
|
||||
vjs.TOUCH_ENABLED = true;
|
||||
|
||||
var comp = new vjs.Component(getFakePlayer(), {});
|
||||
|
||||
comp.emitTapEvents();
|
||||
comp.on('tap', function(){
|
||||
ok(true, 'Tap event emitted');
|
||||
});
|
||||
comp.trigger('touchstart');
|
||||
comp.trigger('touchend');
|
||||
|
||||
// This second test should not trigger another tap event because
|
||||
// a touchmove is happening
|
||||
comp.trigger('touchstart');
|
||||
comp.trigger('touchmove');
|
||||
comp.trigger('touchend');
|
||||
|
||||
// Reset to orignial value
|
||||
vjs.TOUCH_ENABLED = origTouch;
|
||||
});
|
||||
|
0
test/unit/control-bar.js
Normal file
0
test/unit/control-bar.js
Normal file
@ -21,10 +21,15 @@ test('should re-link the player if the tech is moved', function(){
|
||||
var player, tech, el;
|
||||
el = document.createElement('div');
|
||||
el.innerHTML = '<div />';
|
||||
|
||||
player = {
|
||||
id: function(){ return 'id'; },
|
||||
el: function(){ return el; },
|
||||
options_: {},
|
||||
options: function(){ return {}; },
|
||||
controls: function(){ return false; },
|
||||
usingNativeControls: function(){ return false; },
|
||||
on: function(){ return this; },
|
||||
ready: function(){}
|
||||
};
|
||||
tech = new vjs.Html5(player, {});
|
||||
@ -32,4 +37,4 @@ test('should re-link the player if the tech is moved', function(){
|
||||
tech.createEl();
|
||||
|
||||
strictEqual(player, tech.el()['player']);
|
||||
});
|
||||
});
|
||||
|
@ -211,20 +211,29 @@ test('should be able to initialize player twice on the same tag using string ref
|
||||
player.dispose();
|
||||
});
|
||||
|
||||
test('should set controls and trigger event', function() {
|
||||
expect(3);
|
||||
test('should set controls and trigger events', function() {
|
||||
expect(6);
|
||||
|
||||
var player = PlayerTest.makePlayer({ 'controls': false });
|
||||
ok(player.controls() === false, 'controls set through options');
|
||||
var hasDisabledClass = player.el().className.indexOf('vjs-controls-disabled');
|
||||
ok(hasDisabledClass !== -1, 'Disabled class added to player');
|
||||
|
||||
player.controls(true);
|
||||
ok(player.controls() === true, 'controls updated');
|
||||
var hasEnabledClass = player.el().className.indexOf('vjs-controls-enabled');
|
||||
ok(hasEnabledClass !== -1, 'Disabled class added to player');
|
||||
|
||||
player.on('controlschange', function(){
|
||||
ok(true, 'controlschange fired once');
|
||||
player.on('controlsenabled', function(){
|
||||
ok(true, 'enabled fired once');
|
||||
});
|
||||
player.on('controlsdisabled', function(){
|
||||
ok(true, 'disabled fired once');
|
||||
});
|
||||
player.controls(false);
|
||||
// Check for unnecessary controlschange events
|
||||
player.controls(false);
|
||||
player.controls(true);
|
||||
// Check for unnecessary events
|
||||
player.controls(true);
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
@ -247,3 +256,76 @@ test('should set controls and trigger event', function() {
|
||||
// player.requestFullScreen();
|
||||
// });
|
||||
|
||||
test('should toggle user the user state between active and inactive', function(){
|
||||
var player = PlayerTest.makePlayer({});
|
||||
|
||||
expect(9);
|
||||
|
||||
ok(player.userActive(), 'User should be active at player init');
|
||||
|
||||
player.on('userinactive', function(){
|
||||
ok(true, 'userinactive event triggered');
|
||||
});
|
||||
|
||||
player.on('useractive', function(){
|
||||
ok(true, 'useractive event triggered');
|
||||
});
|
||||
|
||||
player.userActive(false);
|
||||
ok(player.userActive() === false, 'Player state changed to inactive');
|
||||
ok(player.el().className.indexOf('vjs-user-active') === -1, 'Active class removed');
|
||||
ok(player.el().className.indexOf('vjs-user-inactive') !== -1, 'Inactive class added');
|
||||
|
||||
player.userActive(true);
|
||||
ok(player.userActive() === true, 'Player state changed to active');
|
||||
ok(player.el().className.indexOf('vjs-user-inactive') === -1, 'Inactive class removed');
|
||||
ok(player.el().className.indexOf('vjs-user-active') !== -1, 'Active class added');
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
||||
test('should add a touch-enabled classname when touch is supported', function(){
|
||||
var player;
|
||||
|
||||
expect(1);
|
||||
|
||||
// Fake touch support. Real touch support isn't needed for this test.
|
||||
var origTouch = vjs.TOUCH_ENABLED;
|
||||
vjs.TOUCH_ENABLED = true;
|
||||
|
||||
player = PlayerTest.makePlayer({});
|
||||
|
||||
ok(player.el().className.indexOf('vjs-touch-enabled'), 'touch-enabled classname added');
|
||||
|
||||
|
||||
vjs.TOUCH_ENABLED = origTouch;
|
||||
player.dispose();
|
||||
});
|
||||
|
||||
test('should allow for tracking when native controls are used', function(){
|
||||
var player = PlayerTest.makePlayer({});
|
||||
|
||||
expect(6);
|
||||
|
||||
// Make sure native controls is false before starting test
|
||||
player.usingNativeControls(false);
|
||||
|
||||
player.on('usingnativecontrols', function(){
|
||||
ok(true, 'usingnativecontrols event triggered');
|
||||
});
|
||||
|
||||
player.on('usingcustomcontrols', function(){
|
||||
ok(true, 'usingcustomcontrols event triggered');
|
||||
});
|
||||
|
||||
player.usingNativeControls(true);
|
||||
ok(player.usingNativeControls() === true, 'Using native controls is true');
|
||||
ok(player.el().className.indexOf('vjs-using-native-controls') !== -1, 'Native controls class added');
|
||||
|
||||
player.usingNativeControls(false);
|
||||
ok(player.usingNativeControls() === false, 'Using native controls is false');
|
||||
ok(player.el().className.indexOf('vjs-using-native-controls') === -1, 'Native controls class removed');
|
||||
|
||||
player.dispose();
|
||||
});
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user