2012-12-30 21:45:50 -08:00
|
|
|
/**
|
2013-01-10 13:06:12 -08:00
|
|
|
* Main player class. A player instance is returned by _V_(id);
|
2012-12-30 21:45:50 -08:00
|
|
|
* @param {Element} tag The original video tag used for configuring options
|
|
|
|
* @param {Object=} options Player options
|
|
|
|
* @param {Function=} ready Ready callback function
|
|
|
|
* @constructor
|
|
|
|
*/
|
2013-04-09 13:43:35 -07:00
|
|
|
vjs.Player = vjs.Component.extend({
|
|
|
|
/** @constructor */
|
|
|
|
init: function(tag, options, ready){
|
|
|
|
this.tag = tag; // Store the original tag used to set options
|
|
|
|
|
|
|
|
// Set Options
|
|
|
|
// The options argument overrides options set in the video tag
|
|
|
|
// which overrides globally set options.
|
|
|
|
// This latter part coincides with the load order
|
|
|
|
// (tag must exist before Player)
|
|
|
|
options = vjs.obj.merge(this.getTagSettings(tag), options);
|
|
|
|
|
|
|
|
// Cache for video property values.
|
|
|
|
this.cache_ = {};
|
|
|
|
|
|
|
|
// Set poster
|
|
|
|
this.poster_ = options['poster'];
|
|
|
|
// Set controls
|
|
|
|
this.controls_ = options['controls'];
|
2013-08-09 14:29:22 -07:00
|
|
|
// 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;
|
2013-04-09 13:43:35 -07:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2013-08-09 14:29:22 -07:00
|
|
|
// 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');
|
|
|
|
// }
|
|
|
|
|
2013-04-09 13:43:35 -07:00
|
|
|
// Firstplay event implimentation. Not sold on the event yet.
|
|
|
|
// Could probably just check currentTime==0?
|
|
|
|
this.one('play', function(e){
|
|
|
|
var fpEvent = { type: 'firstplay', target: this.el_ };
|
|
|
|
// Using vjs.trigger so we can check if default was prevented
|
|
|
|
var keepGoing = vjs.trigger(this.el_, fpEvent);
|
|
|
|
|
|
|
|
if (!keepGoing) {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
e.stopImmediatePropagation();
|
|
|
|
}
|
|
|
|
});
|
2013-01-17 20:33:53 -05:00
|
|
|
|
2013-04-09 13:43:35 -07:00
|
|
|
this.on('ended', this.onEnded);
|
|
|
|
this.on('play', this.onPlay);
|
|
|
|
this.on('firstplay', this.onFirstPlay);
|
|
|
|
this.on('pause', this.onPause);
|
|
|
|
this.on('progress', this.onProgress);
|
|
|
|
this.on('durationchange', this.onDurationChange);
|
|
|
|
this.on('error', this.onError);
|
|
|
|
this.on('fullscreenchange', this.onFullscreenChange);
|
|
|
|
|
|
|
|
// Make player easily findable by ID
|
|
|
|
vjs.players[this.id_] = this;
|
|
|
|
|
|
|
|
if (options['plugins']) {
|
|
|
|
vjs.obj.each(options['plugins'], function(key, val){
|
|
|
|
this[key](val);
|
|
|
|
}, this);
|
|
|
|
}
|
2013-08-09 14:29:22 -07:00
|
|
|
|
|
|
|
this.listenForUserActivity();
|
2013-02-04 10:31:53 -08:00
|
|
|
}
|
2013-04-09 13:43:35 -07:00
|
|
|
});
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2013-01-21 16:19:46 -08:00
|
|
|
/**
|
|
|
|
* Player instance options, surfaced using vjs.options
|
|
|
|
* vjs.options = vjs.Player.prototype.options_
|
|
|
|
* Make changes in vjs.options, not here.
|
|
|
|
* All options should use string keys so they avoid
|
|
|
|
* renaming by closure compiler
|
|
|
|
* @type {Object}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
vjs.Player.prototype.options_ = vjs.options;
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.dispose = function(){
|
2013-07-18 14:39:14 -07:00
|
|
|
this.trigger('dispose');
|
|
|
|
// prevent dispose from being called twice
|
|
|
|
this.off('dispose');
|
2012-04-06 16:42:09 -07:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Kill reference to this player
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.players[this.id_] = null;
|
2013-01-16 20:24:38 -05:00
|
|
|
if (this.tag && this.tag['player']) { this.tag['player'] = null; }
|
|
|
|
if (this.el_ && this.el_['player']) { this.el_['player'] = null; }
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Ensure that tracking progress and time progress will stop and plater deleted
|
2012-12-31 15:25:56 -08:00
|
|
|
this.stopTrackingProgress();
|
2013-01-17 20:33:53 -05:00
|
|
|
this.stopTrackingCurrentTime();
|
2012-04-06 16:42:09 -07:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
if (this.tech) { this.tech.dispose(); }
|
2012-04-06 17:14:45 -07:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Component dispose
|
2013-04-09 13:43:35 -07:00
|
|
|
vjs.Component.prototype.dispose.call(this);
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.getTagSettings = function(tag){
|
2012-12-30 21:45:50 -08:00
|
|
|
var options = {
|
2013-01-10 13:06:12 -08:00
|
|
|
'sources': [],
|
|
|
|
'tracks': []
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2013-01-25 17:36:40 -08:00
|
|
|
vjs.obj.merge(options, vjs.getAttributeValues(tag));
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Get tag children settings
|
|
|
|
if (tag.hasChildNodes()) {
|
2013-06-28 13:06:50 -07:00
|
|
|
var children, child, childName, i, j;
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2013-06-28 13:06:50 -07:00
|
|
|
children = tag.childNodes;
|
|
|
|
|
|
|
|
for (i=0,j=children.length; i<j; i++) {
|
2012-12-30 21:45:50 -08:00
|
|
|
child = children[i];
|
|
|
|
// Change case needed: http://ejohn.org/blog/nodename-case-sensitivity/
|
|
|
|
childName = child.nodeName.toLowerCase();
|
2013-01-10 13:06:12 -08:00
|
|
|
if (childName === 'source') {
|
|
|
|
options['sources'].push(vjs.getAttributeValues(child));
|
|
|
|
} else if (childName === 'track') {
|
|
|
|
options['tracks'].push(vjs.getAttributeValues(child));
|
2011-11-30 13:06:32 -08:00
|
|
|
}
|
|
|
|
}
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
2013-01-10 13:06:12 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
return options;
|
|
|
|
};
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.createEl = function(){
|
2013-04-09 13:43:35 -07:00
|
|
|
var el = this.el_ = vjs.Component.prototype.createEl.call(this, 'div');
|
2012-12-30 21:45:50 -08:00
|
|
|
var tag = this.tag;
|
|
|
|
|
|
|
|
// Remove width/height attrs from tag so CSS can make it 100% width/height
|
2013-01-10 13:06:12 -08:00
|
|
|
tag.removeAttribute('width');
|
|
|
|
tag.removeAttribute('height');
|
2012-12-30 21:45:50 -08:00
|
|
|
// Empty video tag sources and tracks so the built-in player doesn't use them also.
|
|
|
|
// This may not be fast enough to stop HTML5 browsers from reading the tags
|
|
|
|
// so we'll need to turn off any default tracks if we're manually doing
|
|
|
|
// captions and subtitles. videoElement.textTracks
|
|
|
|
if (tag.hasChildNodes()) {
|
2013-06-28 13:06:50 -07:00
|
|
|
var nodes, nodesLength, i, node, nodeName, removeNodes;
|
|
|
|
|
|
|
|
nodes = tag.childNodes;
|
|
|
|
nodesLength = nodes.length;
|
|
|
|
removeNodes = [];
|
|
|
|
|
|
|
|
while (nodesLength--) {
|
|
|
|
node = nodes[nodesLength];
|
|
|
|
nodeName = node.nodeName.toLowerCase();
|
|
|
|
if (nodeName === 'source' || nodeName === 'track') {
|
|
|
|
removeNodes.push(node);
|
2011-11-29 11:40:05 -08:00
|
|
|
}
|
|
|
|
}
|
2013-06-28 13:06:50 -07:00
|
|
|
|
|
|
|
for (i=0; i<removeNodes.length; i++) {
|
|
|
|
tag.removeChild(removeNodes[i]);
|
|
|
|
}
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Make sure tag ID exists
|
2013-01-10 13:06:12 -08:00
|
|
|
tag.id = tag.id || 'vjs_video_' + vjs.guid++;
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Give video tag ID and class to player div
|
|
|
|
// ID will now reference player box, not the video tag
|
|
|
|
el.id = tag.id;
|
|
|
|
el.className = tag.className;
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Update tag id/class for use as HTML5 playback tech
|
|
|
|
// Might think we should do this after embedding in container so .vjs-tech class
|
|
|
|
// doesn't flash 100% width/height, but class only applies with .video-js parent
|
2013-01-10 13:06:12 -08:00
|
|
|
tag.id += '_html5_api';
|
|
|
|
tag.className = 'vjs-tech';
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Make player findable on elements
|
2013-01-16 20:24:38 -05:00
|
|
|
tag['player'] = el['player'] = this;
|
2012-12-30 21:45:50 -08:00
|
|
|
// Default state of video is paused
|
2013-01-10 13:06:12 -08:00
|
|
|
this.addClass('vjs-paused');
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2013-03-05 18:35:55 +02:00
|
|
|
// Make box use width/height of tag, or rely on default implementation
|
2012-12-30 21:45:50 -08:00
|
|
|
// Enforce with CSS since width/height attrs don't work on divs
|
2013-01-17 21:03:25 -05:00
|
|
|
this.width(this.options_['width'], true); // (true) Skip resize listener on load
|
|
|
|
this.height(this.options_['height'], true);
|
2013-04-04 11:06:13 -07:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Wrap video tag in div (el/box) container
|
|
|
|
if (tag.parentNode) {
|
|
|
|
tag.parentNode.insertBefore(el, tag);
|
|
|
|
}
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.insertFirst(tag, el); // Breaks iPhone, fixed in HTML5 setup.
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
return el;
|
2013-01-10 13:06:12 -08:00
|
|
|
};
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
// /* Media Technology (tech)
|
|
|
|
// ================================================================================ */
|
|
|
|
// Load/Create an instance of playback technlogy including element and API methods
|
|
|
|
// And append playback element in player div.
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.loadTech = function(techName, source){
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
// Pause and remove current playback technology
|
|
|
|
if (this.tech) {
|
|
|
|
this.unloadTech();
|
|
|
|
|
|
|
|
// If the first time loading, HTML5 tag will exist but won't be initialized
|
|
|
|
// So we need to remove it if we're not loading HTML5
|
2013-01-10 13:06:12 -08:00
|
|
|
} else if (techName !== 'Html5' && this.tag) {
|
2012-12-30 21:45:50 -08:00
|
|
|
this.el_.removeChild(this.tag);
|
2013-06-28 15:42:47 -07:00
|
|
|
this.tag['player'] = null;
|
2012-12-30 21:45:50 -08:00
|
|
|
this.tag = null;
|
|
|
|
}
|
2012-01-05 23:25:09 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
this.techName = techName;
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Turn off API access because we're loading a new tech that might load asynchronously
|
|
|
|
this.isReady_ = false;
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
var techReady = function(){
|
2013-01-16 20:24:38 -05:00
|
|
|
this.player_.triggerReady();
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-31 15:25:56 -08:00
|
|
|
// Manually track progress in cases where the browser/flash player doesn't report it.
|
2013-08-25 18:50:59 -07:00
|
|
|
if (!this.features['progressEvents']) {
|
2013-01-16 20:24:38 -05:00
|
|
|
this.player_.manualProgressOn();
|
2012-12-31 15:25:56 -08:00
|
|
|
}
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-31 15:25:56 -08:00
|
|
|
// Manually track timeudpates in cases where the browser/flash player doesn't report it.
|
2013-08-25 18:50:59 -07:00
|
|
|
if (!this.features['timeupdateEvents']) {
|
2013-01-16 20:24:38 -05:00
|
|
|
this.player_.manualTimeUpdatesOn();
|
2012-12-31 15:25:56 -08:00
|
|
|
}
|
2013-01-10 13:06:12 -08:00
|
|
|
};
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Grab tech-specific options from player options and add source and parent element to use.
|
2013-02-15 23:31:31 +03:00
|
|
|
var techOptions = vjs.obj.merge({ 'source': source, 'parentEl': this.el_ }, this.options_[techName.toLowerCase()]);
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
if (source) {
|
|
|
|
if (source.src == this.cache_.src && this.cache_.currentTime > 0) {
|
2013-01-10 13:06:12 -08:00
|
|
|
techOptions['startTime'] = this.cache_.currentTime;
|
2011-11-29 11:40:05 -08:00
|
|
|
}
|
2012-04-25 15:15:33 -07:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
this.cache_.src = source.src;
|
|
|
|
}
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Initialize tech instance
|
2013-01-04 16:58:23 -08:00
|
|
|
this.tech = new window['videojs'][techName](this, techOptions);
|
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
this.tech.ready(techReady);
|
|
|
|
};
|
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.Player.prototype.unloadTech = function(){
|
2013-04-04 11:06:13 -07:00
|
|
|
this.isReady_ = false;
|
2013-01-10 13:06:12 -08:00
|
|
|
this.tech.dispose();
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
// Turn off any manual progress or timeupdate tracking
|
|
|
|
if (this.manualProgress) { this.manualProgressOff(); }
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
if (this.manualTimeUpdates) { this.manualTimeUpdatesOff(); }
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
this.tech = false;
|
|
|
|
};
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
// There's many issues around changing the size of a Flash (or other plugin) object.
|
|
|
|
// First is a plugin reload issue in Firefox that has been around for 11 years: https://bugzilla.mozilla.org/show_bug.cgi?id=90268
|
|
|
|
// Then with the new fullscreen API, Mozilla and webkit browsers will reload the flash object after going to fullscreen.
|
|
|
|
// To get around this, we're unloading the tech, caching source and currentTime values, and reloading the tech once the plugin is resized.
|
|
|
|
// reloadTech: function(betweenFn){
|
2013-01-10 13:06:12 -08:00
|
|
|
// vjs.log('unloadingTech')
|
2012-12-30 21:45:50 -08:00
|
|
|
// this.unloadTech();
|
2013-01-10 13:06:12 -08:00
|
|
|
// vjs.log('unloadedTech')
|
2012-12-30 21:45:50 -08:00
|
|
|
// if (betweenFn) { betweenFn.call(); }
|
2013-01-10 13:06:12 -08:00
|
|
|
// vjs.log('LoadingTech')
|
2012-12-30 21:45:50 -08:00
|
|
|
// this.loadTech(this.techName, { src: this.cache_.src })
|
2013-01-10 13:06:12 -08:00
|
|
|
// vjs.log('loadedTech')
|
2012-12-30 21:45:50 -08:00
|
|
|
// },
|
|
|
|
|
|
|
|
/* Fallbacks for unsupported event types
|
2011-11-29 11:40:05 -08:00
|
|
|
================================================================================ */
|
2012-12-30 21:45:50 -08:00
|
|
|
// Manually trigger progress events based on changes to the buffered amount
|
|
|
|
// Many flash players and older HTML5 browsers don't send progress or progress-like events
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.manualProgressOn = function(){
|
2012-12-31 15:25:56 -08:00
|
|
|
this.manualProgress = true;
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2012-12-31 15:25:56 -08:00
|
|
|
// Trigger progress watching when a source begins loading
|
|
|
|
this.trackProgress();
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2012-12-31 15:25:56 -08:00
|
|
|
// Watch for a native progress event call on the tech element
|
|
|
|
// In HTML5, some older versions don't support the progress event
|
|
|
|
// So we're assuming they don't, and turning off manual progress if they do.
|
|
|
|
// As opposed to doing user agent detection
|
2013-01-10 13:06:12 -08:00
|
|
|
this.tech.one('progress', function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2012-12-31 15:25:56 -08:00
|
|
|
// Update known progress support for this playback technology
|
2013-08-25 18:50:59 -07:00
|
|
|
this.features['progressEvents'] = true;
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2012-12-31 15:25:56 -08:00
|
|
|
// Turn off manual progress tracking
|
2013-01-16 20:24:38 -05:00
|
|
|
this.player_.manualProgressOff();
|
2012-12-31 15:25:56 -08:00
|
|
|
});
|
|
|
|
};
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.manualProgressOff = function(){
|
2012-12-31 15:25:56 -08:00
|
|
|
this.manualProgress = false;
|
|
|
|
this.stopTrackingProgress();
|
|
|
|
};
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.trackProgress = function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
this.progressInterval = setInterval(vjs.bind(this, function(){
|
2012-12-31 15:25:56 -08:00
|
|
|
// Don't trigger unless buffered amount is greater than last time
|
|
|
|
// log(this.cache_.bufferEnd, this.buffered().end(0), this.duration())
|
|
|
|
/* TODO: update for multiple buffered regions */
|
|
|
|
if (this.cache_.bufferEnd < this.buffered().end(0)) {
|
2013-01-10 13:06:12 -08:00
|
|
|
this.trigger('progress');
|
2012-12-31 15:25:56 -08:00
|
|
|
} else if (this.bufferedPercent() == 1) {
|
|
|
|
this.stopTrackingProgress();
|
2013-01-10 13:06:12 -08:00
|
|
|
this.trigger('progress'); // Last update
|
2012-12-31 15:25:56 -08:00
|
|
|
}
|
|
|
|
}), 500);
|
|
|
|
};
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.stopTrackingProgress = function(){ clearInterval(this.progressInterval); };
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2012-12-31 15:25:56 -08:00
|
|
|
/* Time Tracking -------------------------------------------------------------- */
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.manualTimeUpdatesOn = function(){
|
2012-12-31 15:25:56 -08:00
|
|
|
this.manualTimeUpdates = true;
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
this.on('play', this.trackCurrentTime);
|
|
|
|
this.on('pause', this.stopTrackingCurrentTime);
|
2012-12-31 15:25:56 -08:00
|
|
|
// timeupdate is also called by .currentTime whenever current time is set
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2012-12-31 15:25:56 -08:00
|
|
|
// Watch for native timeupdate event
|
2013-01-10 13:06:12 -08:00
|
|
|
this.tech.one('timeupdate', function(){
|
2012-12-31 15:25:56 -08:00
|
|
|
// Update known progress support for this playback technology
|
2013-08-25 18:50:59 -07:00
|
|
|
this.features['timeupdateEvents'] = true;
|
2012-12-31 15:25:56 -08:00
|
|
|
// Turn off manual progress tracking
|
2013-01-16 20:24:38 -05:00
|
|
|
this.player_.manualTimeUpdatesOff();
|
2012-12-31 15:25:56 -08:00
|
|
|
});
|
|
|
|
};
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.manualTimeUpdatesOff = function(){
|
2012-12-31 15:25:56 -08:00
|
|
|
this.manualTimeUpdates = false;
|
|
|
|
this.stopTrackingCurrentTime();
|
2013-01-10 13:06:12 -08:00
|
|
|
this.off('play', this.trackCurrentTime);
|
|
|
|
this.off('pause', this.stopTrackingCurrentTime);
|
2012-12-31 15:25:56 -08:00
|
|
|
};
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.trackCurrentTime = function(){
|
2012-12-31 15:25:56 -08:00
|
|
|
if (this.currentTimeInterval) { this.stopTrackingCurrentTime(); }
|
2013-01-04 16:58:23 -08:00
|
|
|
this.currentTimeInterval = setInterval(vjs.bind(this, function(){
|
2013-01-10 13:06:12 -08:00
|
|
|
this.trigger('timeupdate');
|
2012-12-31 15:25:56 -08:00
|
|
|
}), 250); // 42 = 24 fps // 250 is what Webkit uses // FF uses 15
|
|
|
|
};
|
|
|
|
|
|
|
|
// Turn off play progress tracking (when paused or dragging)
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.stopTrackingCurrentTime = function(){ clearInterval(this.currentTimeInterval); };
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
// /* Player event handlers (how the player reacts to certain events)
|
|
|
|
// ================================================================================ */
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.onEnded = function(){
|
2013-01-17 21:03:25 -05:00
|
|
|
if (this.options_['loop']) {
|
2012-12-30 21:45:50 -08:00
|
|
|
this.currentTime(0);
|
|
|
|
this.play();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.onPlay = function(){
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.removeClass(this.el_, 'vjs-paused');
|
|
|
|
vjs.addClass(this.el_, 'vjs-playing');
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
|
|
|
|
2013-02-10 22:45:00 -08:00
|
|
|
vjs.Player.prototype.onFirstPlay = function(){
|
|
|
|
//If the first starttime attribute is specified
|
|
|
|
//then we will start at the given offset in seconds
|
|
|
|
if(this.options_['starttime']){
|
|
|
|
this.currentTime(this.options_['starttime']);
|
|
|
|
}
|
2013-08-09 14:29:22 -07:00
|
|
|
|
|
|
|
this.addClass('vjs-has-started');
|
2013-02-10 22:45:00 -08:00
|
|
|
};
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.onPause = function(){
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.removeClass(this.el_, 'vjs-playing');
|
|
|
|
vjs.addClass(this.el_, 'vjs-paused');
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.onProgress = function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
// Add custom event for when source is finished downloading.
|
|
|
|
if (this.bufferedPercent() == 1) {
|
2013-01-10 13:06:12 -08:00
|
|
|
this.trigger('loadedalldata');
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Update duration with durationchange event
|
|
|
|
// Allows for cacheing value instead of asking player each time.
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.onDurationChange = function(){
|
2013-01-10 13:06:12 -08:00
|
|
|
this.duration(this.techGet('duration'));
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.onError = function(e) {
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.log('Video Error', e);
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
|
|
|
|
2013-05-28 15:29:42 -07:00
|
|
|
vjs.Player.prototype.onFullscreenChange = function() {
|
2013-02-08 01:11:33 +03:00
|
|
|
if (this.isFullScreen) {
|
|
|
|
this.addClass('vjs-fullscreen');
|
|
|
|
} else {
|
|
|
|
this.removeClass('vjs-fullscreen');
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// /* Player API
|
|
|
|
// ================================================================================ */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Object for cached values.
|
|
|
|
* @private
|
|
|
|
*/
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.cache_;
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.getCache = function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
return this.cache_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Pass values to the playback tech
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.techCall = function(method, arg){
|
2012-12-30 21:45:50 -08:00
|
|
|
// If it's not ready yet, call method when it is
|
2013-05-31 10:31:18 -07:00
|
|
|
if (this.tech && !this.tech.isReady_) {
|
2012-12-30 21:45:50 -08:00
|
|
|
this.tech.ready(function(){
|
|
|
|
this[method](arg);
|
|
|
|
});
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Otherwise call method now
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
this.tech[method](arg);
|
|
|
|
} catch(e) {
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.log(e);
|
2013-05-02 17:07:05 -07:00
|
|
|
throw e;
|
2012-02-02 19:16:45 -08:00
|
|
|
}
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
|
|
|
};
|
2012-02-02 19:16:45 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Get calls can't wait for the tech, and sometimes don't need to.
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.techGet = function(method){
|
2012-02-03 10:28:00 -08:00
|
|
|
|
2013-08-26 16:31:07 -07:00
|
|
|
if (this.tech && this.tech.isReady_) {
|
2012-02-03 10:28:00 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Flash likes to die and reload when you hide or reposition it.
|
|
|
|
// In these cases the object methods go away and we get errors.
|
|
|
|
// When that happens we'll catch the errors and inform tech that it's not ready any more.
|
|
|
|
try {
|
|
|
|
return this.tech[method]();
|
|
|
|
} catch(e) {
|
|
|
|
// When building additional tech libs, an expected method may not be defined yet
|
|
|
|
if (this.tech[method] === undefined) {
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.log('Video.js: ' + method + ' method not defined for '+this.techName+' playback technology.', e);
|
2012-12-30 21:45:50 -08:00
|
|
|
} else {
|
|
|
|
// When a method isn't available on the object it throws a TypeError
|
2013-01-10 13:06:12 -08:00
|
|
|
if (e.name == 'TypeError') {
|
|
|
|
vjs.log('Video.js: ' + method + ' unavailable on '+this.techName+' playback technology element.', e);
|
2012-12-30 21:45:50 -08:00
|
|
|
this.tech.isReady_ = false;
|
|
|
|
} else {
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.log(e);
|
2012-02-03 10:28:00 -08:00
|
|
|
}
|
|
|
|
}
|
2013-05-02 17:07:05 -07:00
|
|
|
throw e;
|
2011-11-29 11:40:05 -08:00
|
|
|
}
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
2012-02-03 10:28:00 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
return;
|
|
|
|
};
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2013-01-17 20:33:53 -05:00
|
|
|
/**
|
|
|
|
* Start media playback
|
|
|
|
* http://dev.w3.org/html5/spec/video.html#dom-media-play
|
|
|
|
* We're triggering the 'play' event here instead of relying on the
|
|
|
|
* media element to allow using event.preventDefault() to stop
|
|
|
|
* play from happening if desired. Usecase: preroll ads.
|
|
|
|
*/
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.play = function(){
|
2013-04-08 16:23:41 -07:00
|
|
|
this.techCall('play');
|
2012-12-30 21:45:50 -08:00
|
|
|
return this;
|
|
|
|
};
|
2011-12-05 11:28:18 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// http://dev.w3.org/html5/spec/video.html#dom-media-pause
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.pause = function(){
|
2013-01-10 13:06:12 -08:00
|
|
|
this.techCall('pause');
|
2012-12-30 21:45:50 -08:00
|
|
|
return this;
|
|
|
|
};
|
2011-12-05 11:28:18 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// http://dev.w3.org/html5/spec/video.html#dom-media-paused
|
|
|
|
// The initial state of paused should be true (in Safari it's actually false)
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.paused = function(){
|
2013-01-10 13:06:12 -08:00
|
|
|
return (this.techGet('paused') === false) ? false : true;
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// http://dev.w3.org/html5/spec/video.html#dom-media-currenttime
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.currentTime = function(seconds){
|
2012-12-30 21:45:50 -08:00
|
|
|
if (seconds !== undefined) {
|
2011-12-05 11:28:18 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Cache the last set value for smoother scrubbing.
|
|
|
|
this.cache_.lastSetCurrentTime = seconds;
|
2012-01-05 23:25:09 -08:00
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
this.techCall('setCurrentTime', seconds);
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Improve the accuracy of manual timeupdates
|
2013-01-10 13:06:12 -08:00
|
|
|
if (this.manualTimeUpdates) { this.trigger('timeupdate'); }
|
2012-04-25 15:15:33 -07:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
return this;
|
|
|
|
}
|
2012-04-25 15:15:33 -07:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Cache last currentTime and return
|
|
|
|
// Default to 0 seconds
|
2013-01-10 13:06:12 -08:00
|
|
|
return this.cache_.currentTime = (this.techGet('currentTime') || 0);
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2012-04-25 15:15:33 -07:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// http://dev.w3.org/html5/spec/video.html#dom-media-duration
|
|
|
|
// Duration should return NaN if not available. ParseFloat will turn false-ish values to NaN.
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.duration = function(seconds){
|
2012-12-30 21:45:50 -08:00
|
|
|
if (seconds !== undefined) {
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Cache the last set value for optimiized scrubbing (esp. Flash)
|
|
|
|
this.cache_.duration = parseFloat(seconds);
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
return this;
|
|
|
|
}
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
return this.cache_.duration;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Calculates how much time is left. Not in spec, but useful.
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.remainingTime = function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
return this.duration() - this.currentTime();
|
|
|
|
};
|
|
|
|
|
|
|
|
// http://dev.w3.org/html5/spec/video.html#dom-media-buffered
|
2013-01-10 13:06:12 -08:00
|
|
|
// Buffered returns a timerange object.
|
|
|
|
// Kind of like an array of portions of the video that have been downloaded.
|
2012-12-30 21:45:50 -08:00
|
|
|
// So far no browsers return more than one range (portion)
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.buffered = function(){
|
2013-01-10 13:06:12 -08:00
|
|
|
var buffered = this.techGet('buffered'),
|
2012-12-30 21:45:50 -08:00
|
|
|
start = 0,
|
2013-07-29 15:48:25 -07:00
|
|
|
buflast = buffered.length - 1,
|
2013-01-10 13:06:12 -08:00
|
|
|
// Default end to 0 and store in values
|
|
|
|
end = this.cache_.bufferEnd = this.cache_.bufferEnd || 0;
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-07-29 15:48:25 -07:00
|
|
|
if (buffered && buflast >= 0 && buffered.end(buflast) !== end) {
|
|
|
|
end = buffered.end(buflast);
|
2012-12-30 21:45:50 -08:00
|
|
|
// Storing values allows them be overridden by setBufferedFromProgress
|
|
|
|
this.cache_.bufferEnd = end;
|
|
|
|
}
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
return vjs.createTimeRange(start, end);
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Calculates amount of buffer is full. Not in spec but useful.
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.bufferedPercent = function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
return (this.duration()) ? this.buffered().end(0) / this.duration() : 0;
|
|
|
|
};
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// http://dev.w3.org/html5/spec/video.html#dom-media-volume
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.volume = function(percentAsDecimal){
|
2012-12-30 21:45:50 -08:00
|
|
|
var vol;
|
2012-04-09 14:53:03 -07:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
if (percentAsDecimal !== undefined) {
|
|
|
|
vol = Math.max(0, Math.min(1, parseFloat(percentAsDecimal))); // Force value to between 0 and 1
|
|
|
|
this.cache_.volume = vol;
|
2013-01-10 13:06:12 -08:00
|
|
|
this.techCall('setVolume', vol);
|
|
|
|
vjs.setLocalStorage('volume', vol);
|
2012-12-30 21:45:50 -08:00
|
|
|
return this;
|
|
|
|
}
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Default to 1 when returning current volume.
|
2013-01-10 13:06:12 -08:00
|
|
|
vol = parseFloat(this.techGet('volume'));
|
2012-12-30 21:45:50 -08:00
|
|
|
return (isNaN(vol)) ? 1 : vol;
|
|
|
|
};
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// http://dev.w3.org/html5/spec/video.html#attr-media-muted
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.muted = function(muted){
|
2012-12-30 21:45:50 -08:00
|
|
|
if (muted !== undefined) {
|
2013-01-10 13:06:12 -08:00
|
|
|
this.techCall('setMuted', muted);
|
2012-12-30 21:45:50 -08:00
|
|
|
return this;
|
|
|
|
}
|
2013-01-10 13:06:12 -08:00
|
|
|
return this.techGet('muted') || false; // Default to false
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2012-01-05 23:25:09 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Check if current tech can support native fullscreen (e.g. with built in controls lik iOS, so not our flash swf)
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.Player.prototype.supportsFullScreen = function(){ return this.techGet('supportsFullScreen') || false; };
|
2012-01-29 20:03:44 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Turn on fullscreen (or window) mode
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.requestFullScreen = function(){
|
|
|
|
var requestFullScreen = vjs.support.requestFullScreen;
|
2012-12-30 21:45:50 -08:00
|
|
|
this.isFullScreen = true;
|
2012-02-13 17:51:52 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
if (requestFullScreen) {
|
2013-04-19 20:48:09 -04:00
|
|
|
// the browser supports going fullscreen at the element level so we can
|
|
|
|
// take the controls fullscreen as well as the video
|
2012-02-13 17:51:52 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Trigger fullscreenchange event after change
|
2013-05-28 15:29:42 -07:00
|
|
|
// We have to specifically add this each time, and remove
|
|
|
|
// when cancelling fullscreen. Otherwise if there's multiple
|
|
|
|
// players on a page, they would all be reacting to the same fullscreen
|
|
|
|
// events
|
|
|
|
vjs.on(document, requestFullScreen.eventName, vjs.bind(this, function(e){
|
2012-12-30 21:45:50 -08:00
|
|
|
this.isFullScreen = document[requestFullScreen.isFullScreen];
|
2012-02-13 17:51:52 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// If cancelling fullscreen, remove event listener.
|
2013-01-10 13:06:12 -08:00
|
|
|
if (this.isFullScreen === false) {
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.off(document, requestFullScreen.eventName, arguments.callee);
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
2012-01-05 23:25:09 -08:00
|
|
|
|
2013-05-28 15:29:42 -07:00
|
|
|
this.trigger('fullscreenchange');
|
2012-12-30 21:45:50 -08:00
|
|
|
}));
|
2012-01-05 23:25:09 -08:00
|
|
|
|
2013-05-28 15:29:42 -07:00
|
|
|
this.el_[requestFullScreen.requestFn]();
|
2013-05-06 10:44:59 -07:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
} else if (this.tech.supportsFullScreen()) {
|
2013-04-19 20:48:09 -04:00
|
|
|
// we can't take the video.js controls fullscreen but we can go fullscreen
|
|
|
|
// with native controls
|
|
|
|
this.techCall('enterFullScreen');
|
2012-12-30 21:45:50 -08:00
|
|
|
} else {
|
2013-04-19 20:48:09 -04:00
|
|
|
// fullscreen isn't supported so we'll just stretch the video element to
|
|
|
|
// fill the viewport
|
2012-12-30 21:45:50 -08:00
|
|
|
this.enterFullWindow();
|
2013-05-06 10:44:59 -07:00
|
|
|
this.trigger('fullscreenchange');
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
2012-01-05 23:25:09 -08:00
|
|
|
|
2013-04-19 20:48:09 -04:00
|
|
|
return this;
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2012-02-13 17:42:22 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.cancelFullScreen = function(){
|
|
|
|
var requestFullScreen = vjs.support.requestFullScreen;
|
2012-12-30 21:45:50 -08:00
|
|
|
this.isFullScreen = false;
|
2012-01-05 23:25:09 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Check for browser element fullscreen support
|
|
|
|
if (requestFullScreen) {
|
2013-05-28 15:29:42 -07:00
|
|
|
document[requestFullScreen.cancelFn]();
|
2013-05-06 10:44:59 -07:00
|
|
|
} else if (this.tech.supportsFullScreen()) {
|
2013-04-19 20:48:09 -04:00
|
|
|
this.techCall('exitFullScreen');
|
2012-12-30 21:45:50 -08:00
|
|
|
} else {
|
|
|
|
this.exitFullWindow();
|
2013-01-10 13:06:12 -08:00
|
|
|
this.trigger('fullscreenchange');
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
return this;
|
|
|
|
};
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// When fullscreen isn't supported we can stretch the video container to as wide as the browser will let us.
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.enterFullWindow = function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
this.isFullWindow = true;
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Storing original doc overflow value to return to when fullscreen is off
|
|
|
|
this.docOrigOverflow = document.documentElement.style.overflow;
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Add listener for esc key to exit fullscreen
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.on(document, 'keydown', vjs.bind(this, this.fullWindowOnEscKey));
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Hide any scroll bars
|
|
|
|
document.documentElement.style.overflow = 'hidden';
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Apply fullscreen styles
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.addClass(document.body, 'vjs-full-window');
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
this.trigger('enterFullWindow');
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.fullWindowOnEscKey = function(event){
|
2013-01-10 13:06:12 -08:00
|
|
|
if (event.keyCode === 27) {
|
|
|
|
if (this.isFullScreen === true) {
|
2012-12-30 21:45:50 -08:00
|
|
|
this.cancelFullScreen();
|
|
|
|
} else {
|
|
|
|
this.exitFullWindow();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.exitFullWindow = function(){
|
2012-12-30 21:45:50 -08:00
|
|
|
this.isFullWindow = false;
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.off(document, 'keydown', this.fullWindowOnEscKey);
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Unhide scroll bars.
|
|
|
|
document.documentElement.style.overflow = this.docOrigOverflow;
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Remove fullscreen styles
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.removeClass(document.body, 'vjs-full-window');
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Resize the box, controller, and poster to original sizes
|
|
|
|
// this.positionAll();
|
2013-01-10 13:06:12 -08:00
|
|
|
this.trigger('exitFullWindow');
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.selectSource = function(sources){
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Loop through each playback technology in the options order
|
2013-01-17 21:03:25 -05:00
|
|
|
for (var i=0,j=this.options_['techOrder'];i<j.length;i++) {
|
2013-01-04 16:58:23 -08:00
|
|
|
var techName = vjs.capitalize(j[i]),
|
|
|
|
tech = window['videojs'][techName];
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Check if the browser supports this technology
|
2012-12-31 15:25:56 -08:00
|
|
|
if (tech.isSupported()) {
|
2012-12-30 21:45:50 -08:00
|
|
|
// Loop through each source object
|
|
|
|
for (var a=0,b=sources;a<b.length;a++) {
|
|
|
|
var source = b[a];
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Check if source can be played with this technology
|
2012-12-31 15:25:56 -08:00
|
|
|
if (tech['canPlaySource'](source)) {
|
2012-12-30 21:45:50 -08:00
|
|
|
return { source: source, tech: techName };
|
2012-02-02 14:56:47 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
// src is a pretty powerful function
|
|
|
|
// If you pass it an array of source objects, it will find the best source to play and use that object.src
|
|
|
|
// If the new source requires a new playback technology, it will switch to that.
|
|
|
|
// If you pass it an object, it will set the source to object.src
|
|
|
|
// If you pass it anything else (url string) it will set the video source to that
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.src = function(source){
|
2012-12-30 21:45:50 -08:00
|
|
|
// Case: Array of source objects to choose from and pick the best to play
|
|
|
|
if (source instanceof Array) {
|
|
|
|
|
|
|
|
var sourceTech = this.selectSource(source),
|
|
|
|
techName;
|
|
|
|
|
|
|
|
if (sourceTech) {
|
|
|
|
source = sourceTech.source;
|
|
|
|
techName = sourceTech.tech;
|
|
|
|
|
|
|
|
// If this technology is already loaded, set source
|
|
|
|
if (techName == this.techName) {
|
|
|
|
this.src(source); // Passing the source object
|
|
|
|
// Otherwise load this technology with chosen source
|
2012-02-02 14:56:47 -08:00
|
|
|
} else {
|
2012-12-30 21:45:50 -08:00
|
|
|
this.loadTech(techName, source);
|
2011-11-29 11:40:05 -08:00
|
|
|
}
|
2012-12-30 21:45:50 -08:00
|
|
|
} else {
|
2013-01-10 13:48:41 -08:00
|
|
|
this.el_.appendChild(vjs.createEl('p', {
|
2013-08-27 10:26:32 -07:00
|
|
|
innerHTML: this.options()['notSupportedMessage']
|
2013-01-10 13:48:41 -08:00
|
|
|
}));
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
// Case: Source object { src: '', type: '' ... }
|
2012-12-30 21:45:50 -08:00
|
|
|
} else if (source instanceof Object) {
|
2012-02-02 14:56:47 -08:00
|
|
|
|
2013-01-04 16:58:23 -08:00
|
|
|
if (window['videojs'][this.techName]['canPlaySource'](source)) {
|
2012-12-30 21:45:50 -08:00
|
|
|
this.src(source.src);
|
2011-11-29 11:40:05 -08:00
|
|
|
} else {
|
2012-12-30 21:45:50 -08:00
|
|
|
// Send through tech loop to check for a compatible technology.
|
|
|
|
this.src([source]);
|
|
|
|
}
|
2012-01-05 23:25:09 -08:00
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Case: URL String (http://myvideo...)
|
|
|
|
} else {
|
|
|
|
// Cache for getting last set source
|
|
|
|
this.cache_.src = source;
|
|
|
|
|
|
|
|
if (!this.isReady_) {
|
|
|
|
this.ready(function(){
|
|
|
|
this.src(source);
|
|
|
|
});
|
|
|
|
} else {
|
2013-01-10 13:06:12 -08:00
|
|
|
this.techCall('src', source);
|
2013-01-17 21:03:25 -05:00
|
|
|
if (this.options_['preload'] == 'auto') {
|
2012-12-30 21:45:50 -08:00
|
|
|
this.load();
|
|
|
|
}
|
2013-01-17 21:03:25 -05:00
|
|
|
if (this.options_['autoplay']) {
|
2012-12-30 21:45:50 -08:00
|
|
|
this.play();
|
2011-12-01 15:47:12 -08:00
|
|
|
}
|
2011-11-29 11:40:05 -08:00
|
|
|
}
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Begin loading the src data
|
|
|
|
// http://dev.w3.org/html5/spec/video.html#dom-media-load
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.load = function(){
|
2013-01-10 13:06:12 -08:00
|
|
|
this.techCall('load');
|
2012-12-30 21:45:50 -08:00
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
// http://dev.w3.org/html5/spec/video.html#dom-media-currentsrc
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.currentSrc = function(){
|
2013-01-10 13:06:12 -08:00
|
|
|
return this.techGet('currentSrc') || this.cache_.src || '';
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Attributes/Options
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.preload = function(value){
|
2012-12-30 21:45:50 -08:00
|
|
|
if (value !== undefined) {
|
2013-01-10 13:06:12 -08:00
|
|
|
this.techCall('setPreload', value);
|
2013-01-17 21:03:25 -05:00
|
|
|
this.options_['preload'] = value;
|
2011-11-29 11:40:05 -08:00
|
|
|
return this;
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
2013-01-10 13:06:12 -08:00
|
|
|
return this.techGet('preload');
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.autoplay = function(value){
|
2012-12-30 21:45:50 -08:00
|
|
|
if (value !== undefined) {
|
2013-01-10 13:06:12 -08:00
|
|
|
this.techCall('setAutoplay', value);
|
2013-01-17 21:03:25 -05:00
|
|
|
this.options_['autoplay'] = value;
|
2011-11-29 11:40:05 -08:00
|
|
|
return this;
|
2012-12-30 21:45:50 -08:00
|
|
|
}
|
2013-01-10 13:06:12 -08:00
|
|
|
return this.techGet('autoplay', value);
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
2013-01-04 16:58:23 -08:00
|
|
|
vjs.Player.prototype.loop = function(value){
|
2012-12-30 21:45:50 -08:00
|
|
|
if (value !== undefined) {
|
2013-01-10 13:06:12 -08:00
|
|
|
this.techCall('setLoop', value);
|
2013-01-17 21:03:25 -05:00
|
|
|
this.options_['loop'] = value;
|
2012-12-30 21:45:50 -08:00
|
|
|
return this;
|
|
|
|
}
|
2013-01-10 13:06:12 -08:00
|
|
|
return this.techGet('loop');
|
2012-12-30 21:45:50 -08:00
|
|
|
};
|
|
|
|
|
2013-01-18 18:06:15 -08:00
|
|
|
/**
|
|
|
|
* The url of the poster image source.
|
|
|
|
* @type {String}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
vjs.Player.prototype.poster_;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get or set the poster image source url.
|
|
|
|
* @param {String} src Poster image source URL
|
2013-01-25 17:36:40 -08:00
|
|
|
* @return {String} Poster image source URL or null
|
2013-01-18 18:06:15 -08:00
|
|
|
*/
|
|
|
|
vjs.Player.prototype.poster = function(src){
|
|
|
|
if (src !== undefined) {
|
|
|
|
this.poster_ = src;
|
|
|
|
}
|
|
|
|
return this.poster_;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether or not the controls are showing
|
|
|
|
* @type {Boolean}
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
vjs.Player.prototype.controls_;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get or set whether or not the controls are showing.
|
|
|
|
* @param {Boolean} controls Set controls to showing or not
|
|
|
|
* @return {Boolean} Controls are showing
|
|
|
|
*/
|
2013-08-09 14:29:22 -07:00
|
|
|
vjs.Player.prototype.controls = function(bool){
|
|
|
|
if (bool !== undefined) {
|
|
|
|
bool = !!bool; // force boolean
|
2013-05-02 17:07:05 -07:00
|
|
|
// Don't trigger a change event unless it actually changed
|
2013-08-09 14:29:22 -07:00
|
|
|
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');
|
|
|
|
}
|
2013-05-02 17:07:05 -07:00
|
|
|
}
|
2013-08-09 14:29:22 -07:00
|
|
|
return this;
|
2013-01-18 18:06:15 -08:00
|
|
|
}
|
|
|
|
return this.controls_;
|
|
|
|
};
|
|
|
|
|
2013-08-09 14:29:22 -07:00
|
|
|
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_;
|
|
|
|
};
|
|
|
|
|
2013-01-10 13:06:12 -08:00
|
|
|
vjs.Player.prototype.error = function(){ return this.techGet('error'); };
|
|
|
|
vjs.Player.prototype.ended = function(){ return this.techGet('ended'); };
|
2013-08-23 15:05:04 -07:00
|
|
|
vjs.Player.prototype.seeking = function(){ return this.techGet('seeking'); };
|
2012-12-30 21:45:50 -08:00
|
|
|
|
2013-08-09 14:29:22 -07:00
|
|
|
// 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);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2012-12-30 21:45:50 -08:00
|
|
|
// Methods to add support for
|
2013-01-10 13:06:12 -08:00
|
|
|
// networkState: function(){ return this.techCall('networkState'); },
|
|
|
|
// readyState: function(){ return this.techCall('readyState'); },
|
|
|
|
// seeking: function(){ return this.techCall('seeking'); },
|
|
|
|
// initialTime: function(){ return this.techCall('initialTime'); },
|
|
|
|
// startOffsetTime: function(){ return this.techCall('startOffsetTime'); },
|
|
|
|
// played: function(){ return this.techCall('played'); },
|
|
|
|
// seekable: function(){ return this.techCall('seekable'); },
|
|
|
|
// videoTracks: function(){ return this.techCall('videoTracks'); },
|
|
|
|
// audioTracks: function(){ return this.techCall('audioTracks'); },
|
|
|
|
// videoWidth: function(){ return this.techCall('videoWidth'); },
|
|
|
|
// videoHeight: function(){ return this.techCall('videoHeight'); },
|
|
|
|
// defaultPlaybackRate: function(){ return this.techCall('defaultPlaybackRate'); },
|
|
|
|
// playbackRate: function(){ return this.techCall('playbackRate'); },
|
|
|
|
// mediaGroup: function(){ return this.techCall('mediaGroup'); },
|
|
|
|
// controller: function(){ return this.techCall('controller'); },
|
|
|
|
// defaultMuted: function(){ return this.techCall('defaultMuted'); }
|
2012-12-30 21:45:50 -08:00
|
|
|
|
|
|
|
// TODO
|
|
|
|
// currentSrcList: the array of sources including other formats and bitrates
|
|
|
|
// playList: array of source lists in order of playback
|
2011-11-29 11:40:05 -08:00
|
|
|
|
2012-01-05 23:25:09 -08:00
|
|
|
// RequestFullscreen API
|
|
|
|
(function(){
|
2013-04-19 20:48:09 -04:00
|
|
|
var prefix, requestFS, div;
|
|
|
|
|
|
|
|
div = document.createElement('div');
|
|
|
|
|
|
|
|
requestFS = {};
|
2012-01-05 23:25:09 -08:00
|
|
|
|
|
|
|
// Current W3C Spec
|
|
|
|
// http://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html#api
|
|
|
|
// Mozilla Draft: https://wiki.mozilla.org/Gecko:FullScreenAPI#fullscreenchange_event
|
2013-05-28 15:29:42 -07:00
|
|
|
// New: https://dvcs.w3.org/hg/fullscreen/raw-file/529a67b8d9f3/Overview.html
|
2013-04-19 20:48:09 -04:00
|
|
|
if (div.cancelFullscreen !== undefined) {
|
|
|
|
requestFS.requestFn = 'requestFullscreen';
|
|
|
|
requestFS.cancelFn = 'exitFullscreen';
|
|
|
|
requestFS.eventName = 'fullscreenchange';
|
|
|
|
requestFS.isFullScreen = 'fullScreen';
|
2012-01-05 23:25:09 -08:00
|
|
|
|
2013-04-29 14:44:07 -04:00
|
|
|
// Webkit (Chrome/Safari) and Mozilla (Firefox) have working implementations
|
2013-04-19 20:48:09 -04:00
|
|
|
// that use prefixes and vary slightly from the new W3C spec. Specifically,
|
|
|
|
// using 'exit' instead of 'cancel', and lowercasing the 'S' in Fullscreen.
|
|
|
|
// Other browsers don't have any hints of which version they might follow yet,
|
|
|
|
// so not going to try to predict by looping through all prefixes.
|
2012-01-05 23:25:09 -08:00
|
|
|
} else {
|
|
|
|
|
2013-04-19 20:48:09 -04:00
|
|
|
if (document.mozCancelFullScreen) {
|
|
|
|
prefix = 'moz';
|
|
|
|
requestFS.isFullScreen = prefix + 'FullScreen';
|
|
|
|
} else {
|
|
|
|
prefix = 'webkit';
|
|
|
|
requestFS.isFullScreen = prefix + 'IsFullScreen';
|
|
|
|
}
|
2012-01-29 20:03:44 -08:00
|
|
|
|
2013-04-19 20:48:09 -04:00
|
|
|
if (div[prefix + 'RequestFullScreen']) {
|
|
|
|
requestFS.requestFn = prefix + 'RequestFullScreen';
|
|
|
|
requestFS.cancelFn = prefix + 'CancelFullScreen';
|
2013-01-10 13:06:12 -08:00
|
|
|
}
|
2013-04-19 20:48:09 -04:00
|
|
|
requestFS.eventName = prefix + 'fullscreenchange';
|
2012-01-05 23:25:09 -08:00
|
|
|
}
|
|
|
|
|
2013-04-19 20:48:09 -04:00
|
|
|
if (document[requestFS.cancelFn]) {
|
|
|
|
vjs.support.requestFullScreen = requestFS;
|
2012-01-05 23:25:09 -08:00
|
|
|
}
|
|
|
|
|
2012-05-25 11:59:53 +02:00
|
|
|
})();
|
2013-08-09 14:29:22 -07:00
|
|
|
|
|
|
|
|