Skip to content

Commit

Permalink
Modernized the fullscreen API and added support for IE11. fixes #1155 c…
Browse files Browse the repository at this point in the history
…loses #1205
  • Loading branch information
heff committed May 15, 2014
1 parent 97c1f83 commit 46aa551
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 101 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ CHANGELOG
* Updated captions/subtiles file fetching to support cross-origin requests in older IE browsers [[view](https://github.com/videojs/video.js/pull/1095)]
* Added support for playback rate switching [[view](https://github.com/videojs/video.js/pull/1132)]
* Fixed an issue with the loadstart event order that caused the big play button to not hide [[view](https://github.com/videojs/video.js/pull/1209)]
* Modernized the fullscreen API and added support for IE11 [[view](https://github.com/videojs/video.js/pull/1205)]

--------------------

Expand Down
1 change: 1 addition & 0 deletions build/source-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var sourceFiles = [
"src/js/slider.js",
"src/js/menu.js",
"src/js/media-error.js",
"src/js/fullscreen-api.js",
"src/js/player.js",
"src/js/control-bar/control-bar.js",
"src/js/control-bar/live-display.js",
Expand Down
22 changes: 20 additions & 2 deletions src/js/button.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,34 @@ vjs.Button = vjs.Component.extend({
});

vjs.Button.prototype.createEl = function(type, props){
var el;

// Add standard Aria and Tabindex info
props = vjs.obj.merge({
className: this.buildCSSClass(),
innerHTML: '<div class="vjs-control-content"><span class="vjs-control-text">' + (this.buttonText || 'Need Text') + '</span></div>',
'role': 'button',
'aria-live': 'polite', // let the screen reader user know that the text of the button may change
tabIndex: 0
}, props);

return vjs.Component.prototype.createEl.call(this, type, props);
el = vjs.Component.prototype.createEl.call(this, type, props);

// if innerHTML hasn't been overridden (bigPlayButton), add content elements
if (!props.innerHTML) {
this.contentEl_ = vjs.createEl('div', {
className: 'vjs-control-content'
});

this.controlText_ = vjs.createEl('span', {
className: 'vjs-control-text',
innerHTML: this.buttonText || 'Need Text'
});

this.contentEl_.appendChild(this.controlText_);
el.appendChild(this.contentEl_);
}

return el;
};

vjs.Button.prototype.buildCSSClass = function(){
Expand Down
10 changes: 5 additions & 5 deletions src/js/control-bar/fullscreen-toggle.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ vjs.FullscreenToggle.prototype.buildCSSClass = function(){
};

vjs.FullscreenToggle.prototype.onClick = function(){
if (!this.player_.isFullScreen()) {
this.player_.requestFullScreen();
this.el_.children[0].children[0].innerHTML = 'Non-Fullscreen'; // change the button text to "Non-Fullscreen"
if (!this.player_.isFullscreen()) {
this.player_.requestFullscreen();
this.controlText_.innerHTML = 'Non-Fullscreen';
} else {
this.player_.cancelFullScreen();
this.el_.children[0].children[0].innerHTML = 'Fullscreen'; // change the button to "Fullscreen"
this.player_.exitFullscreen();
this.controlText_.innerHTML = 'Fullscreen';
}
};
82 changes: 82 additions & 0 deletions src/js/fullscreen-api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
(function(){
var apiMap, specApi, browserApi, i;

/**
* Store the browser-specifc methods for the fullscreen API
* @type {Object|undefined}
* @private
*/
vjs.browser.fullscreenAPI;

// browser API methods
// map approach from Screenful.js - https://github.com/sindresorhus/screenfull.js
apiMap = [
// Spec: https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html
[
'requestFullscreen',
'exitFullscreen',
'fullscreenElement',
'fullscreenEnabled',
'fullscreenchange',
'fullscreenerror'
],
// WebKit
[
'webkitRequestFullscreen',
'webkitExitFullscreen',
'webkitFullscreenElement',
'webkitFullscreenEnabled',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
// Old WebKit (Safari 5.1)
[
'webkitRequestFullScreen',
'webkitCancelFullScreen',
'webkitCurrentFullScreenElement',
'webkitCancelFullScreen',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
// Mozilla
[
'mozRequestFullScreen',
'mozCancelFullScreen',
'mozFullScreenElement',
'mozFullScreenEnabled',
'mozfullscreenchange',
'mozfullscreenerror'
],
// Microsoft
[
'msRequestFullscreen',
'msExitFullscreen',
'msFullscreenElement',
'msFullscreenEnabled',
'MSFullscreenChange',
'MSFullscreenError'
]
];

specApi = apiMap[0];

// determine the supported set of functions
for (i=0; i<apiMap.length; i++) {
// check for exitFullscreen function
if (apiMap[i][1] in document) {
browserApi = apiMap[i];
break;
}
}

// map the browser API names to the spec API names
// or leave vjs.browser.fullscreenAPI undefined
if (browserApi) {
vjs.browser.fullscreenAPI = {};

for (i=0; i<browserApi.length; i++) {
vjs.browser.fullscreenAPI[specApi[i]] = browserApi[i];
}
}

})();
2 changes: 1 addition & 1 deletion src/js/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ vjs.insertFirst = function(child, parent){
* @type {Object}
* @private
*/
vjs.support = {};
vjs.browser = {};

/**
* Shorthand for document.getElementById()
Expand Down
9 changes: 6 additions & 3 deletions src/js/player.externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,12 @@ videojs.Player.prototype.poster = function(){};
/**
* Fullscreen functionality
*/
videojs.Player.prototype.isFullScreen = function(){};
videojs.Player.prototype.requestFullScreen = function(){};
videojs.Player.prototype.cancelFullScreen = function(){};
videojs.Player.prototype.isFullscreen = function(){};
videojs.Player.prototype.isFullScreen = function(){}; /* deprecated */
videojs.Player.prototype.requestFullscreen = function(){};
videojs.Player.prototype.requestFullScreen = function(){}; /* deprecated */
videojs.Player.prototype.exitFullscreen = function(){};
videojs.Player.prototype.cancelFullScreen = function(){}; /* deprecated */

/**
* Text tracks
Expand Down
130 changes: 56 additions & 74 deletions src/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ vjs.Player.prototype.onVolumeChange;
* @event fullscreenchange
*/
vjs.Player.prototype.onFullscreenChange = function() {
if (this.isFullScreen()) {
if (this.isFullscreen()) {
this.addClass('vjs-fullscreen');
} else {
this.removeClass('vjs-fullscreen');
Expand Down Expand Up @@ -842,37 +842,46 @@ vjs.Player.prototype.supportsFullScreen = function(){
* @type {Boolean}
* @private
*/
vjs.Player.prototype.isFullScreen_ = false;
vjs.Player.prototype.isFullscreen_ = false;

/**
* Check if the player is in fullscreen mode
*
* // get
* var fullscreenOrNot = myPlayer.isFullScreen();
* var fullscreenOrNot = myPlayer.isFullscreen();
*
* // set
* myPlayer.isFullScreen(true); // tell the player it's in fullscreen
* myPlayer.isFullscreen(true); // tell the player it's in fullscreen
*
* NOTE: As of the latest HTML5 spec, isFullScreen is no longer an official
* property and instead document.fullscreenElement is used. But isFullScreen is
* NOTE: As of the latest HTML5 spec, isFullscreen is no longer an official
* property and instead document.fullscreenElement is used. But isFullscreen is
* still a valuable property for internal player workings.
*
* @param {Boolean=} isFS Update the player's fullscreen state
* @return {Boolean} true if fullscreen, false if not
* @return {vjs.Player} self, when setting
*/
vjs.Player.prototype.isFullScreen = function(isFS){
vjs.Player.prototype.isFullscreen = function(isFS){
if (isFS !== undefined) {
this.isFullScreen_ = isFS;
this.isFullscreen_ = !!isFS;
return this;
}
return this.isFullScreen_;
return this.isFullscreen_;
};

/**
* Old naming for isFullscreen()
* @deprecated for lowercase 's' version
*/
vjs.Player.prototype.isFullScreen = function(isFS){
vjs.log.warn('player.isFullScreen() has been deprecated, use player.isFullscreen() with a lowercase "s")');
return this.isFullscreen(isFS);
};

/**
* Increase the size of the video to full screen
*
* myPlayer.requestFullScreen();
* myPlayer.requestFullscreen();
*
* In some browsers, full screen is not supported natively, so it enters
* "full window mode", where the video fills the browser window.
Expand All @@ -883,11 +892,12 @@ vjs.Player.prototype.isFullScreen = function(isFS){
*
* @return {vjs.Player} self
*/
vjs.Player.prototype.requestFullScreen = function(){
var requestFullScreen = vjs.support.requestFullScreen;
this.isFullScreen(true);
vjs.Player.prototype.requestFullscreen = function(){
var fsApi = vjs.browser.fullscreenAPI;

this.isFullscreen(true);

if (requestFullScreen) {
if (fsApi) {
// the browser supports going fullscreen at the element level so we can
// take the controls fullscreen as well as the video

Expand All @@ -896,18 +906,18 @@ vjs.Player.prototype.requestFullScreen = function(){
// 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){
this.isFullScreen(document[requestFullScreen.isFullScreen]);
vjs.on(document, fsApi.fullscreenchange, vjs.bind(this, function(e){
this.isFullscreen(document[fsApi.fullscreenElement]);

// If cancelling fullscreen, remove event listener.
if (this.isFullScreen() === false) {
vjs.off(document, requestFullScreen.eventName, arguments.callee);
if (this.isFullscreen() === false) {
vjs.off(document, fsApi.fullscreenchange, arguments.callee);
}

this.trigger('fullscreenchange');
}));

this.el_[requestFullScreen.requestFn]();
this.el_[fsApi.requestFullscreen]();

} else if (this.tech.supportsFullScreen()) {
// we can't take the video.js controls fullscreen but we can go fullscreen
Expand All @@ -923,20 +933,30 @@ vjs.Player.prototype.requestFullScreen = function(){
return this;
};

/**
* Old naming for requestFullscreen
* @deprecated for lower case 's' version
*/
vjs.Player.prototype.requestFullScreen = function(){
vjs.log.warn('player.requestFullScreen() has been deprecated, use player.requestFullscreen() with a lowercase "s")');
return this.requestFullscreen();
};


/**
* Return the video to its normal size after having been in full screen mode
*
* myPlayer.cancelFullScreen();
* myPlayer.exitFullscreen();
*
* @return {vjs.Player} self
*/
vjs.Player.prototype.cancelFullScreen = function(){
var requestFullScreen = vjs.support.requestFullScreen;
this.isFullScreen(false);
vjs.Player.prototype.exitFullscreen = function(){
var fsApi = vjs.browser.fullscreenAPI;
this.isFullscreen(false);

// Check for browser element fullscreen support
if (requestFullScreen) {
document[requestFullScreen.cancelFn]();
if (fsApi) {
document[fsApi.exitFullscreen]();
} else if (this.tech.supportsFullScreen()) {
this.techCall('exitFullScreen');
} else {
Expand All @@ -947,6 +967,15 @@ vjs.Player.prototype.cancelFullScreen = function(){
return this;
};

/**
* Old naming for exitFullscreen
* @deprecated for exitFullscreen
*/
vjs.Player.prototype.cancelFullScreen = function(){
vjs.log.warn('player.cancelFullScreen() has been deprecated, use player.exitFullscreen()');
return this.exitFullscreen();
};

// When fullscreen isn't supported we can stretch the video container to as wide as the browser will let us.
vjs.Player.prototype.enterFullWindow = function(){
this.isFullWindow = true;
Expand All @@ -967,8 +996,8 @@ vjs.Player.prototype.enterFullWindow = function(){
};
vjs.Player.prototype.fullWindowOnEscKey = function(event){
if (event.keyCode === 27) {
if (this.isFullScreen() === true) {
this.cancelFullScreen();
if (this.isFullscreen() === true) {
this.exitFullscreen();
} else {
this.exitFullWindow();
}
Expand Down Expand Up @@ -1480,50 +1509,3 @@ vjs.Player.prototype.playbackRate = function(rate) {
// TODO
// currentSrcList: the array of sources including other formats and bitrates
// playList: array of source lists in order of playback

// RequestFullscreen API
(function(){
var prefix, requestFS, div;

div = document.createElement('div');

requestFS = {};

// 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
// New: https://dvcs.w3.org/hg/fullscreen/raw-file/529a67b8d9f3/Overview.html
if (div.cancelFullscreen !== undefined) {
requestFS.requestFn = 'requestFullscreen';
requestFS.cancelFn = 'exitFullscreen';
requestFS.eventName = 'fullscreenchange';
requestFS.isFullScreen = 'fullScreen';

// Webkit (Chrome/Safari) and Mozilla (Firefox) have working implementations
// 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.
} else {

if (document.mozCancelFullScreen) {
prefix = 'moz';
requestFS.isFullScreen = prefix + 'FullScreen';
requestFS.requestFn = prefix + 'RequestFullScreen';
} else {
prefix = 'webkit';
requestFS.isFullScreen = prefix + 'IsFullScreen';
requestFS.requestFn = prefix + 'RequestFullscreen';
}

if (div[prefix + 'RequestFullScreen']) {
requestFS.cancelFn = prefix + 'CancelFullScreen';
}
requestFS.eventName = prefix + 'fullscreenchange';
}

if (document[requestFS.cancelFn]) {
vjs.support.requestFullScreen = requestFS;
}

})();
Loading

0 comments on commit 46aa551

Please sign in to comment.