/**
* Msg text is inherited from embedPlayer
*/
( function( mw, $ ) { "use strict";
/**
* mw.PlayerControlBuilder object
* @param the embedPlayer element we are targeting
*/
mw.PlayerControlBuilder = function( embedPlayer, options ) {
return this.init( embedPlayer, options );
};
/**
* ControlsBuilder prototype:
*/
mw.PlayerControlBuilder.prototype = {
//Default Local values:
// Parent css Class name
playerClass : 'mv-player',
// Long string display of time value
longTimeDisp: true,
// Default volume layout is "vertical"
volumeLayout : 'vertical',
// Default control bar height
height: mw.config.get( 'EmbedPlayer.ControlsHeight' ),
// Default supported components is merged with embedPlayer set of supported types
supportedComponents: {
// All playback types support options
'options': true
},
// Default supported menu items is merged with skin menu items
supportedMenuItems: {
// Player Select
'playerSelect' : true,
// Download the file menu
'download' : true,
// Share the video menu
'share' : true,
// Player library link
'aboutPlayerLibrary': true
},
// Flag to store the current fullscreen mode
inFullScreen: false,
// Flag to store if a warning binding has been added
addWarningFlag: false,
// Flag to store state of overlay on player
displayOptionsMenuFlag: false,
// Local storage of ControlBar Callback
hideControlBarCallback: false,
// Flag to store controls status (disabled/enabled)
controlsDisabled: false,
// binding postfix
bindPostfix: '.controlBuilder',
/**
* Initialization Object for the control builder
*
* @param {Object} embedPlayer EmbedPlayer interface
*/
init: function( embedPlayer ) {
var _this = this;
this.embedPlayer = embedPlayer;
// Check for skin overrides for controlBuilder
var skinClass = embedPlayer.skinName.substr(0,1).toUpperCase() + embedPlayer.skinName.substr( 1 );
if ( mw['PlayerSkin' + skinClass ] ) {
// Clone as to not override prototype with the skin config
_this = $.extend( true, { }, this, mw['PlayerSkin' + skinClass ] );
}
if ( _this.embedPlayer.mediaElement.getPlayableSources().length <= 1
&& _this.supportedMenuItems.playerSelect ) {
delete _this.supportedMenuItems.playerSelect;
}
// Return the controlBuilder Object:
return _this;
},
/**
* Get the control bar height
* @return {Number} control bar height
*/
getHeight: function(){
return this.height;
},
/**
* Add the controls html to player interface
*/
addControls: function() {
// Set up local pointer to the embedPlayer
var embedPlayer = this.embedPlayer,
profile = $.client.profile();
// Set up local controlBuilder
var _this = this;
// Remove any old controls & old overlays:
embedPlayer.getInterface().find( '.control-bar,.overlay-win' ).remove();
// Reset flags:
_this.displayOptionsMenuFlag = false;
// Setup the controlBar container ( starts hidden )
var $controlBar = $('
')
.addClass( 'ui-state-default ui-widget-header ui-helper-clearfix control-bar' )
.css( 'height', this.height );
// Controls are hidden by default if overlaying controls:
if( _this.isOverlayControls() ){
$controlBar.hide();
} else {
// Include the control bar height when calculating the layout
$controlBar.addClass('block');
}
// Make room for audio controls in the interface:
if( embedPlayer.isAudio() && embedPlayer.getInterface().height() == 0 ){
embedPlayer.getInterface().css( {
'height' : this.height
} );
}
// Add the controls to the interface
embedPlayer.getInterface().append( $controlBar );
if ( profile.name === 'firefox' && profile.versionNumber < 2 ) {
embedPlayer.triggerHelper( 'resizeIframeContainer', [ {'height' : embedPlayer.height + $controlBar.height() - 1} ] );
}
// Add the Controls Component
this.addControlComponents();
// Add top level Controls bindings
this.addControlBindings();
},
/**
* Add control components as defined per this.components
*/
addControlComponents: function( ) {
var _this = this;
// Set up local pointer to the embedPlayer
var embedPlayer = this.embedPlayer;
//Set up local var to control container:
var $controlBar = embedPlayer.getInterface().find( '.control-bar' );
this.availableWidth = embedPlayer.getPlayerWidth();
mw.log( 'PlayerControlsBuilder:: addControlComponents into:' + this.availableWidth );
// Build the supportedComponents list
this.supportedComponents = $.extend( this.supportedComponents, embedPlayer.supports );
// Check for Attribution button
if( mw.config.get( 'EmbedPlayer.AttributionButton' ) && embedPlayer.attributionbutton ){
this.supportedComponents[ 'attributionButton' ] = true;
}
// Check global fullscreen enabled flag
if( mw.config.get( 'EmbedPlayer.EnableFullscreen' ) === false ){
this.supportedComponents[ 'fullscreen'] = false;
}
// Check if the options item is available
if( mw.config.get( 'EmbedPlayer.EnableOptionsMenu' ) === false ){
this.supportedComponents[ 'options'] = false;
}
// Check for volume control
if( mw.config.get( 'EmbedPlayer.EnableVolumeControl') === false ){
this.supportedComponents[ 'volumeControl'] = false;
}
// Check if we have multiple playable sources ( if only one source don't display source switch )
if( embedPlayer.mediaElement.getPlayableSources().length == 1 ){
this.supportedComponents[ 'sourceSwitch' ] = false;
}
// Give embeds option to explicitly disable components via flag
var source = embedPlayer.mediaElement.getPlayableSources()[0];
if ( !embedPlayer.disablecontrols && source ) {
embedPlayer.disablecontrols = source.disablecontrols;
}
if ( embedPlayer.disablecontrols ) {
embedPlayer.disablecontrols.split(',').forEach(function( key ) {
mw.log( 'PlayerControlBuilder:: disabled component via flag:' + key );
_this.supportedComponents[ key ] = false;
});
}
$( embedPlayer ).trigger( 'addControlBarComponent', this );
var components = [];
var largestPos = 0;
var addComponent = function( componentId ){
if ( _this.supportedComponents[ componentId ] ) {
if ( _this.availableWidth >= _this.components[ componentId ].w ) {
_this.availableWidth -= _this.components[ componentId ].w;
// Check if position is defined, if not, place at end of known positions
var position = _this.components[ componentId ].position ?
_this.components[ componentId ].position:
largestPos+1
if( position > largestPos ){
largestPos = position;
}
components.push({
'id': componentId,
'position': position
});
//mw.log(" availableWidth:" + _this.availableWidth + ' ' + componentId + ' took: ' + _this.components[ componentId ].w )
} else {
mw.log( 'PlayerControlBuilder:: Not enough space for control component:' + componentId );
}
}
};
var addComponents = function() {
components.sort(function(a, b) {
return b.position - a.position;
});
for(var i=0;i 30 ){
addComponent( 'playHead' );
}
addComponents();
$(embedPlayer).trigger( 'controlBarBuildDone' );
},
/**
* Get a window size for the player while preserving aspect ratio:
*
* @@TODO This has similar logic to mw.embedPlayerNative applyIntrinsicAspect we should look
* at merging their functionality.
*
* @param {object} windowSize
* object that set { 'width': {width}, 'height':{height} } of target window
* @return {object}
* css settings for fullscreen player
*/
getAspectPlayerWindowCss: function( windowSize ) {
var embedPlayer = this.embedPlayer;
var _this = this;
// Setup target height width based on max window size
if( !windowSize ){
var windowSize = {
'width' : $( window ).width(),
'height' : $( window ).height()
};
}
windowSize.width = parseInt( windowSize.width );
windowSize.height = parseInt( windowSize.height );
// See if we need to leave space for control bar
if( !_this.isOverlayControls() ){
//targetHeight = targetHeight - this.height;
windowSize.height = windowSize.height - this.height;
}
// Set target width
var targetWidth = windowSize.width;
var targetHeight = targetWidth * ( 1 / _this.getIntrinsicAspect() );
// Check if it exceeds the height constraint:
if( targetHeight > windowSize.height ){
targetHeight = windowSize.height;
targetWidth = parseInt( targetHeight * _this.getIntrinsicAspect() );
}
var offsetTop = 0;
// Move the video down 1/2 of the difference of window height
offsetTop+= ( targetHeight < windowSize.height )? ( windowSize.height- targetHeight ) / 2 : 0;
// if the video is very tall in a short window adjust the size:
var offsetLeft = ( targetWidth < windowSize.width )? parseInt( windowSize.width- targetWidth ) / 2 : 0;
var position = (mw.isIOS4() && mw.isIphone()) ? 'static' : 'absolute';
mw.log( 'PlayerControlBuilder::getAspectPlayerWindowCss: ' + ' h:' + targetHeight + ' w:' + targetWidth + ' t:' + offsetTop + ' l:' + offsetLeft );
return {
'position' : position,
'height': parseInt( targetHeight ),
'width' : parseInt( targetWidth ),
'top' : parseInt( offsetTop ),
'left': parseInt( offsetLeft)
};
},
/**
* Get the intrinsic aspect ratio of media ( width / height )
* @return {float}
* size object with width and height
*/
getIntrinsicAspect: function(){
var vid = this.embedPlayer.getPlayerElement();
// Check for raw intrinsic media size:
if( vid && vid.videoWidth && vid.videoHeight ){
return vid.videoWidth / vid.videoHeight;
}
// See if we have source data attributes available:
if( this.embedPlayer.mediaElement &&
this.embedPlayer.mediaElement.selectedSource )
{
var ss = this.embedPlayer.mediaElement.selectedSource;
// See if we have a hardcoded aspect to the source ( Adaptive streams don't have width / height )
if( ss.aspect ){
return ss.aspect;
}
if( ss.width && ss.height ){
return ss.width / ss.height
}
}
// check for posterImage size: ( should have Intrinsic aspect size as well )
var img = this.embedPlayer.getInterface().find('.playerPoster')[0];
if( img && img.naturalWidth && img.naturalHeight){
return img.naturalWidth / img.naturalHeight
}
// if all else fails use embedPlayer.getWidth()
return this.embedPlayer.getWidth() / this.embedPlayer.getHeight()
},
/**
* Get the play button css
*/
getPlayButtonPosition: function() {
var _this = this;
return {
'position' : 'absolute',
'left' : '50%',
'top' : '50%',
'margin-left' : - .5 * this.getComponentWidth( 'playButtonLarge' ),
'margin-top' : - .5 * this.getComponentHeight( 'playButtonLarge' )
};
},
/**
* Check if we're in Fullscreen
* @return {boolean)
*/
isInFullScreen: function() {
return this.inFullScreen;
},
/**
* Toggles full screen by calling
* doFullScreenPlayer to enable fullscreen mode
* restoreWindowPlayer to restore window mode
*/
toggleFullscreen: function( forceClose ) {
var _this = this;
// Do normal in-page fullscreen handling:
if( this.isInFullScreen() ){
this.restoreWindowPlayer();
}else {
this.doFullScreenPlayer();
}
// Don't follow the # link:
return false;
},
/**
* Do full-screen mode
*/
doFullScreenPlayer: function( callback ) {
mw.log("PlayerControlBuilder:: doFullScreenPlayer" );
// Setup pointer to control builder :
var _this = this,
profile = $.client.profile();
// Store the page vertical scroll
var doc = window.document;
var context = window;
this.verticalScrollPosition = doc.all ? doc.scrollTop : context.pageYOffset;
// Setup local reference to embed player:
var embedPlayer = this.embedPlayer;
// Setup a local reference to the player interface:
var $interface = embedPlayer.getInterface();
// Check fullscreen state ( if already true do nothing )
if( this.isInFullScreen() == true ){
return ;
}
this.inFullScreen = true;
// Add fullscreen class to interface:
$interface.addClass( 'fullscreen' );
// if overlaying controls add hide show player binding.
if( _this.isOverlayControls() && !embedPlayer.isTouchDevice() ){
_this.addFullscreenMouseMoveHideShowControls();
}
// Store the current scroll location on the iframe:
$( embedPlayer ).trigger( 'fullScreenStoreVerticalScroll' );
if( window.fullScreenApi.supportsFullScreen ) {
_this.preFullscreenPlayerSize = this.getPlayerSize();
var fullscreenHeight = null;
var fsTarget = this.getFsTarget();
var escapeFullscreen = function( event ) {
// grab the correct document target to check for fullscreen
if ( ! window.fullScreenApi.isFullScreen( window.document ) ) {
_this.restoreWindowPlayer();
}
}
// remove any old binding:
fsTarget.removeEventListener( fullScreenApi.fullScreenEventName, escapeFullscreen );
// Add a binding to catch "escape" fullscreen
fsTarget.addEventListener( fullScreenApi.fullScreenEventName, escapeFullscreen );
// Make the iframe fullscreen:
window.fullScreenApi.requestFullScreen( fsTarget );
// There is a bug with mozfullscreenchange event in all versions of firefox with supportsFullScreen
// https://bugzilla.mozilla.org/show_bug.cgi?id=724816
// so we have to have an extra binding to check for size change and then restore.
if( profile.name === 'firefox' ){
_this.fullscreenRestoreCheck = setInterval( function(){
if( fullscreenHeight && $(window).height() < fullscreenHeight ){
// Mozilla triggered size change:
clearInterval ( _this.fullscreenRestoreCheck );
_this.restoreWindowPlayer();
}
// set fullscreen height:
if( ! fullscreenHeight && _this.preFullscreenPlayerSize.height != $(window).height() ){
fullscreenHeight = $(window).height();
}
}, 250 );
}
} else {
// Check for hybrid html controls / native fullscreen support:
var vid = this.embedPlayer.getPlayerElement();
if( mw.config.get('EmbedPlayer.EnableIpadNativeFullscreen')
&&
vid && vid.webkitSupportsFullscreen
){
this.doHybridNativeFullscreen();
return ;
} else {
// make the player traget or iframe fullscreen
this.doContextTargetFullscreen();
}
}
// Bind escape to restore in page clip ( IE9 needs a secondary escape binding )
$( window ).keyup( function( event ) {
// Escape check
if( event.keyCode == 27 ){
_this.restoreWindowPlayer();
}
} );
// trigger the open fullscreen event:
$( embedPlayer ).trigger( 'onOpenFullScreen' );
// re draw the controls after a timeout ( to allow the screen dom to update )
setTimeout( function(){
_this.addControls();
},100)
},
/**
* Make the target player interface or iframe fullscreen
*/
doContextTargetFullscreen: function() {
var
_this = this,
doc = window.document,
$doc = $( doc ),
$target = $( this.getFsTarget() ),
context = window;
// update / reset local restore properties
this.parentsAbsoluteList = [];
this.parentsRelativeList = [];
// Set the original parent page scale if possible:
this.orginalParnetViewPortContent = $doc.find( 'meta[name="viewport"]' ).attr( 'content' );
this.orginalTargetElementLayout = {
'style' : $target[0].style.cssText,
'width' : $target.width(),
'height' : $target.height()
};
mw.log("PlayerControls:: doParentIframeFullscreen> verticalScrollPosition:" + this.verticalScrollPosition);
context.scroll(0, 0);
// Make sure the parent page page has a zoom of 1:
if( ! $doc.find('meta[name="viewport"]').length ){
$doc.find('head').append( $( '' ).attr('name', 'viewport') );
}
$doc.find('meta[name="viewport"]').attr('content', 'initial-scale=1; maximum-scale=1; minimum-scale=1;' );
// iPad 5 supports fixed position in a bad way, use absolute pos for iOS
var playerCssPosition = ( mw.isIOS() ) ? 'absolute': 'fixed';
// Remove absolute css of the $target's parents
$target.parents().each( function() {
var $parent = $( this );
if( $parent.css( 'position' ) == 'absolute' ) {
_this.parentsAbsoluteList.push( $parent );
$parent.css( 'position', 'static' );
}
if( $parent.css( 'position' ) == 'relative' ) {
_this.parentsRelativeList.push( $parent );
$parent.css( 'position', 'static' );
}
});
// Make the $target fullscreen
$target
.css({
'z-index': mw.config.get( 'EmbedPlayer.FullScreenZIndex' ),
'position': playerCssPosition,
'top' : '0px',
'left' : '0px',
'margin': 0
})
.data(
'isFullscreen', true
);
var updateTargetSize = function() {
context.scroll(0, 0);
$target.css({
'width' : context.innerWidth,
'height' : context.innerHeight
});
// update player size if needed:
_this.embedPlayer.applyIntrinsicAspect();
};
updateTargetSize();
// Bind orientation change to resize player ( if fullscreen )
$( context ).bind( 'orientationchange', function(e){
if( _this.isInFullScreen() ){
updateTargetSize();
}
});
// prevent scrolling when in fullscreen: ( both iframe and dom target use document )
document.ontouchmove = function( e ){
if( _this.isInFullScreen() ){
e.preventDefault();
}
};
},
/**
* Restore the player interface or iframe to a window player
*/
restoreContextPlayer: function(){
var
_this = this,
doc = window.document,
$doc = $( doc ),
$target = $( this.getFsTarget() ),
context = window;
mw.log("PlayerControlsBuilder:: restoreContextPlayer> verticalScrollPosition:" + this.verticalScrollPosition );
// Restore document zoom:
if( this.orginalParnetViewPortContent ){
$doc.find('meta[name="viewport"]').attr('content', this.orginalParnetViewPortContent );
} else {
// Restore user zoom: ( NOTE, there does not appear to be a way to know the
// initial scale, so we just restore to 1 in the absence of explicit viewport tag )
// In order to restore zoom, we must set maximum-scale to a valid value
$doc.find('meta[name="viewport"]').attr('content', 'initial-scale=1; maximum-scale=8; minimum-scale=1;' );
}
if( this.orginalTargetElementLayout ) {
$target[0].style.cssText = this.orginalTargetElementLayout.style;
$target.attr({
'width': this.orginalTargetElementLayout.width,
'height': this.orginalTargetElementLayout.height
});
// update player size if needed:
_this.embedPlayer.applyIntrinsicAspect();
}
// Restore any parent absolute pos:
$doc.find( _this.parentsAbsoluteList ).each( function() {
$( this ).css( 'position', 'absolute' );
} );
$doc.find( _this.parentsRelativeList ).each( function() {
$( this ).css( 'position', 'relative' );
} );
},
/**
* Supports hybrid native fullscreen, player html controls, and fullscreen is native
*/
doHybridNativeFullscreen: function(){
var vid = this.embedPlayer.getPlayerElement();
var _this = this;
vid.webkitEnterFullscreen();
// start to pull for exit fullscreen:
this.fsIntervalID = setInterval( function(){
var currentFS = vid.webkitDisplayingFullscreen;
// Check if we have entered fullscreen but the player
// has exited fullscreen with native controls click
if( _this.isInFullScreen() && !currentFS ){
// restore non-fullscreen player state
_this.inFullScreen = false;
// Trigger the onCloseFullscreen event:
$( _this.embedPlayer ).trigger( 'onCloseFullScreen' );
// stop polling for state change.
clearInterval( _this.fsIntervalID );
}
}, 250 );
},
getWindowSize: function(){
return {
'width' : $(window).width(),
'height' : $(window).height()
};
},
doDomFullscreen: function(){
var _this = this;
var embedPlayer = this.embedPlayer;
var $interface = embedPlayer.getInterface();
// Remove any old mw-fullscreen-overlay
$( '.mw-fullscreen-overlay' ).remove();
_this.preFullscreenPlayerSize = this.getPlayerSize();
// Add the css fixed fullscreen black overlay as a sibling to the video element
// iOS4 does not respect z-index
$interface.after(
$( '' )
.addClass( 'mw-fullscreen-overlay' )
// Set some arbitrary high z-index
.css('z-index', mw.config.get( 'EmbedPlayer.FullScreenZIndex' ) )
.hide()
.fadeIn("slow")
);
// get the original interface to absolute positioned:
if( ! this.windowPositionStyle ){
this.windowPositionStyle = $interface.css( 'position' );
}
if( !this.windowZindex ){
this.windowZindex = $interface.css( 'z-index' );
}
// Get the base offset:
this.windowOffset = this.getWindowOffset();
// Change the z-index of the interface
$interface.css( {
'position' : 'fixed',
'z-index' : mw.config.get( 'EmbedPlayer.FullScreenZIndex' ) + 1,
'top' : this.windowOffset.top,
'left' : this.windowOffset.left
} );
// If native persistent native player update z-index:
if( embedPlayer.isPersistentNativePlayer() ){
$( embedPlayer.getPlayerElement() ).css( {
'z-index': mw.config.get( 'EmbedPlayer.FullScreenZIndex' ) + 1,
'position': 'absolute'
});
}
// Empty out the parent absolute index
_this.parentsAbsolute = [];
// Hide the body scroll bar
$('body').css( 'overflow', 'hidden' );
var topOffset = '0px';
var leftOffset = '0px';
// Check if we have an offsetParent
if( $interface.offsetParent()[0].tagName
&&
$interface.offsetParent()[0].tagName.toLowerCase() != 'body' )
{
topOffset = -this.windowOffset.top + 'px';
leftOffset = -this.windowOffset.left + 'px';
}
// Overflow hidden in fullscreen:
$interface.css( 'overlow', 'hidden' );
// Remove absolute css of the interface parents
$interface.parents().each( function() {
//mw.log(' parent : ' + $( this ).attr('id' ) + ' class: ' + $( this ).attr('class') + ' pos: ' + $( this ).css( 'position' ) );
if( $( this ).css( 'position' ) == 'absolute' ) {
_this.parentsAbsolute.push( $( this ) );
$( this ).css( 'position', null );
mw.log( 'PlayerControlBuilder:: should update position: ' + $( this ).css( 'position' ) );
}
});
// Bind escape to restore in page clip
$( window ).keyup( function( event ) {
// Escape check
if( event.keyCode == 27 ){
_this.restoreWindowPlayer();
}
} );
},
addFullscreenMouseMoveHideShowControls:function(){
var _this = this;
// Bind mouse move in interface to hide control bar
_this.mouseMovedFlag = false;
_this.embedPlayer.getInterface().mousemove( function(e){
_this.mouseMovedFlag = true;
});
// Check every 2 seconds reset flag status if controls are overlay
var checkMovedMouse = function(){
if( _this.isInFullScreen() ){
if( _this.mouseMovedFlag ){
_this.mouseMovedFlag = false;
_this.showControlBar();
// Once we move the mouse keep displayed for 3 seconds
setTimeout(checkMovedMouse, 3000);
} else {
// Check for mouse movement every 250ms
_this.hideControlBar();
setTimeout(checkMovedMouse, 250 );
}
return;
}
};
// always initially show the control bar:
_this.showControlBar();
// start monitoring for moving mouse
checkMovedMouse();
},
getWindowOffset: function(){
var windowOffset = this.embedPlayer.getInterface().offset();
windowOffset.top = windowOffset.top - $(document).scrollTop();
windowOffset.left = windowOffset.left - $(document).scrollLeft();
this.windowOffset = windowOffset;
return this.windowOffset;
},
// Display a fullscreen tip if configured to do and the browser supports it.
displayFullscreenTip: function(){
var _this = this;
// Mobile devices don't have f11 key
if( mw.isMobileDevice() ){
return ;
}
// Safari does not have a DOM fullscreen ( no subtitles, no controls )
if ( $.client.profile().name === 'safari' ) {
return;
}
// OSX has a different short cut than windows and liux
var toolTipMsg = ( navigator.userAgent.indexOf('Mac OS X') != -1 )?
mw.msg( 'mwe-embedplayer-fullscreen-tip-osx') :
mw.msg( 'mwe-embedplayer-fullscreen-tip');
var $targetTip = this.addWarningBinding( 'EmbedPlayer.FullscreenTip',
$('').html(
toolTipMsg
)
);
// Display the target warning:
$targetTip.show();
var hideTip = function(){
mw.setConfig('EmbedPlayer.FullscreenTip', false );
$targetTip.fadeOut('fast');
};
// Hide fullscreen tip if:
// We leave fullscreen,
$( this.embedPlayer ).bind( 'onCloseFullScreen', hideTip );
// After 5 seconds,
setTimeout( hideTip, 5000 );
// Or if we catch an f11 button press
$( document ).keyup( function( event ){
if( event.keyCode == 122 ){
hideTip();
}
return true;
});
},
// TOOD fullscreen iframe vs inpage object abstraction
//( avoid repatiave conditionals in getters )
getPlayerSize: function(){
var height = $(window).height() - this.getHeight();
if( mw.config.get('EmbedPlayer.IsIframeServer' ) ){
return {
'height' : height,
'width' : $(window).width()
}
} else {
return {
'height' : this.embedPlayer.getInterface().height(),
'width' : this.embedPlayer.getInterface().width()
}
}
},
getFsTarget: function(){
var $interface = this.embedPlayer.getInterface();
return $interface[0];
},
/**
* Restore the window player
*/
restoreWindowPlayer: function() {
var _this = this;
mw.log("PlayerControlBuilder :: restoreWindowPlayer" );
var embedPlayer = this.embedPlayer;
// Check if fullscreen mode is already restored:
if( this.isInFullScreen() === false ){
return ;
}
// Set fullscreen mode to false
this.inFullScreen = false;
// remove the fullscreen interface
embedPlayer.getInterface().removeClass( 'fullscreen' );
// Check for native support for fullscreen and support native fullscreen restore
if ( window.fullScreenApi.supportsFullScreen ) {
var fsTarget = this.getFsTarget();
window.fullScreenApi.cancelFullScreen( fsTarget );
}
// Restore the iFrame context player
this.restoreContextPlayer();
// Restore scrolling on iPad
$( document ).unbind( 'touchend.fullscreen' );
// Trigger the onCloseFullscreen event:
$( embedPlayer ).trigger( 'onCloseFullScreen' );
// Scroll back to the previews position ( do in async call to allow dom fullscreen restore )
setTimeout( function(){
window.scroll( 0, _this.verticalScrollPosition );
}, 100 );
// re draw the controls after a timeout ( to allow the screen dom to update )
setTimeout( function(){
_this.addControls();
},100)
},
restoreDomPlayer: function(){
var _this = this;
// local ref to embedPlayer:
var embedPlayer = this.embedPlayer;
var $interface = embedPlayer.$interface;
var interfaceHeight = ( _this.isOverlayControls() )
? embedPlayer.getHeight()
: embedPlayer.getHeight() + _this.getHeight();
mw.log( 'restoreWindowPlayer:: h:' + interfaceHeight + ' w:' + embedPlayer.getWidth());
$('.mw-fullscreen-overlay').remove( 'slow' );
mw.log( 'restore embedPlayer:: ' + embedPlayer.getWidth() + ' h: ' + embedPlayer.getHeight() );
// Restore the player:
embedPlayer.getInterface().css( {
'width' : _this.preFullscreenPlayerSize.width,
'height' : _this.preFullscreenPlayerSize.height
});
var topPos = {
'position' : _this.windowPositionStyle,
'z-index' : _this.windowZindex,
'overlow' : 'visible',
'top' : '0px',
'left' : '0px'
};
// Restore non-absolute layout:
$( [ $interface, $interface.find('.playerPoster'), embedPlayer ] ).css( topPos );
if( embedPlayer.getPlayerElement() ){
$( embedPlayer.getPlayerElement() )
.css( topPos )
}
// Restore the body scroll bar
$('body').css( 'overflow', 'auto' );
// If native player restore z-index:
if( embedPlayer.isPersistentNativePlayer() ){
$( embedPlayer.getPlayerElement() ).css( {
'z-index': 'auto'
});
}
},
/**
* Get minimal width for interface overlay
*/
getOverlayWidth: function( ) {
return ( this.embedPlayer.getPlayerWidth() < 300 )? 300 : this.embedPlayer.getPlayerWidth();
},
/**
* Get minimal height for interface overlay
*/
getOverlayHeight: function( ) {
return ( this.embedPlayer.getPlayerHeight() < 200 )? 200 : this.embedPlayer.getPlayerHeight();
},
/**
* addControlBindings
* Adds control hooks once controls are in the DOM
*/
addControlBindings: function( ) {
// Set up local pointer to the embedPlayer
var embedPlayer = this.embedPlayer,
_this = this,
$interface = embedPlayer.getInterface(),
profile = $.client.profile();
_this.onControlBar = false;
// Remove any old interface bindings
$( embedPlayer ).unbind( this.bindPostfix );
var bindFirstPlay = false;
_this.addRightClickBinding();
// add the player click bindings
_this.addPlayerClickBindings();
// Bind into play.ctrl namespace ( so we can unbind without affecting other play bindings )
$( embedPlayer ).bind( 'onplay' + this.bindPostfix, function() { //Only bind once played
// add right click binding again ( in case the player got swaped )
embedPlayer.controlBuilder.addRightClickBinding();
});
$( embedPlayer ).bind( 'timeupdate' + this.bindPostfix, function(){
embedPlayer.updatePlayheadStatus()
});
// Update buffer information
$( embedPlayer ).bind( 'progress' + this.bindPostfix, function( event, jEvent, id){
// regain scope
var embedPlayer = $( '#' + id )[0];
embedPlayer.updateBufferStatus();
});
// Bind to EnableInterfaceComponents
$( embedPlayer ).bind( 'onEnableInterfaceComponents' + this.bindPostfix, function() {
embedPlayer.controlBuilder.controlsDisabled = false;
embedPlayer.controlBuilder.addPlayerClickBindings();
});
// Bind to DisableInterfaceComponents
$( embedPlayer ).bind( 'onDisableInterfaceComponents' + this.bindPostfix, function() {
embedPlayer.controlBuilder.controlsDisabled = true;
embedPlayer.controlBuilder.removePlayerClickBindings();
});
// TODO select a player on the page
var bindSpaceUp = function(){
$(window).bind('keyup' + _this.bindPostfix, function(e) {
if( e.keyCode == 32 ) {
if(embedPlayer.paused) {
embedPlayer.play();
} else {
embedPlayer.pause();
}
return false;
}
});
};
var bindSpaceDown = function() {
$(window).unbind( 'keyup' + _this.bindPostfix );
};
// Bind to resize event
/*
var triggerUpdate;
$( window ).resize(function() {
// We use setTimeout because of iOS 4.2 issues
clearTimeout(triggerUpdate);
triggerUpdate = setTimeout(function() {
//embedPlayer.triggerHelper('updateLayout');
}, 100);
});
*/
$(window).on("debouncedresize", function() {
embedPlayer.triggerHelper('updateLayout');
});
// Add hide show bindings for control overlay (if overlay is enabled )
if( ! _this.isOverlayControls() ) {
$interface
.show()
.hover( bindSpaceUp, bindSpaceDown );
// include touch start pause binding
$( embedPlayer).bind( 'touchstart' + this.bindPostfix, function() {
embedPlayer._playContorls = true;
mw.log( "PlayerControlBuilder:: touchstart:" + ' isPause:' + embedPlayer.paused);
if( embedPlayer.paused ) {
embedPlayer.play();
} else {
embedPlayer.pause();
}
});
} else { // hide show controls:
// Bind a startTouch to show controls
$( embedPlayer).bind( 'touchstart' + this.bindPostfix, function() {
if ( embedPlayer.getInterface().find( '.control-bar' ).is( ':visible' ) ) {
if( embedPlayer.paused ) {
embedPlayer.play();
} else {
embedPlayer.pause();
}
} else {
_this.showControlBar();
}
clearTimeout( _this.hideControlBarCallback );
_this.hideControlBarCallback = setTimeout( function() {
_this.hideControlBar();
}, 60000 );
// ( Once the user touched the video "don't hide" )
return true;
} );
var hoverIntentConfig = {
'sensitivity': 100,
'timeout' : 1000,
'over' : function(e){
// Clear timeout on IE9
if( mw.isIE9() ) {
clearTimeout(_this.hideControlBarCallback);
_this.hideControlBarCallback = false;
}
// Show controls with a set timeout ( avoid fade in fade out on short mouse over )
_this.showControlBar();
bindSpaceUp();
},
'out' : function(e){
_this.hideControlBar();
bindSpaceDown();
}
};
// Check if we should display the interface:
// special check for IE9 ( does not count hover on non-visiable inerface div
if( mw.isIE9() ){
$( embedPlayer.getPlayerElement() ).hoverIntent( hoverIntentConfig );
// Add hover binding to control bar
embedPlayer.getInterface().find( '.control-bar' ).hover( function(e) {
_this.onControlBar = true;
embedPlayer.getInterface().find( '.control-bar' ).show();
}, function( e ) {
if (!_this.hideControlBarCallback) {
_this.hideControlBarCallback = setTimeout(function(){
_this.hideControlBar();
},1000);
}
_this.onControlBar = false;
});
} else {
if ( !mw.isIpad() ) {
$interface.hoverIntent( hoverIntentConfig );
}
}
}
// Add recommend firefox if we have non-native playback:
if ( _this.checkNativeWarning( ) ) {
_this.addWarningBinding(
'EmbedPlayer.ShowNativeWarning',
mw.msg( 'mwe-embedplayer-for_best_experience',
$('
').append(
$('')
.attr({
'href': 'http://www.mediawiki.org/wiki/Extension:TimedMediaHandler/Client_download',
'target' : '_new'
})
)[0].innerHTML
)
);
}
// Do png fix for ie6
if ( profile.name === 'msie' && profile.versionNumber <= 6 ) {
$( '#' + embedPlayer.id + ' .play-btn-large' ).pngFix();
}
this.doVolumeBinding();
// Check if we have any custom skin Bindings to run
if ( this.addSkinControlBindings && typeof( this.addSkinControlBindings ) == 'function' ){
this.addSkinControlBindings();
}
mw.log( 'trigger::addControlBindingsEvent' );
$( embedPlayer ).trigger( 'addControlBindingsEvent' );
},
removePlayerClickBindings: function(){
$( this.embedPlayer )
.unbind( "click" + this.bindPostfix )
.unbind( "dblclick" + this.bindPostfix );
},
addPlayerClickBindings: function(){
var _this = this;
var embedPlayer = this.embedPlayer;
// prevent scrolling when in fullscreen:
document.ontouchmove = function( e ){
if( _this.isInFullScreen() ){
e.preventDefault();
}
};
// Remove old click bindings before adding:
this.removePlayerClickBindings();
// Setup "dobuleclick" fullscreen binding to embedPlayer ( if enabled )
if ( this.supportedComponents['fullscreen'] ){
$( embedPlayer ).bind( "dblclick" + _this.bindPostfix, function(){
embedPlayer.fullscreen();
});
}
var dblClickTime = 300;
var lastClickTime = 0;
var didDblClick = false;
var playerClickCb = function( event ) {
// make sure the event matches:
if( event.currentTarget.id != embedPlayer.id ){
embedPlayer = $( '#' + event.currentTarget.id )[0];
}
mw.log( "PlayerControlBuilder:: click:" + embedPlayer.id + ' isPause:' + embedPlayer.paused);
// Don't do anything if touch interface or native controls are shown
if( embedPlayer.useNativePlayerControls()
||
_this.isControlsDisabled()
||
embedPlayer.isTouchDevice()
) {
return true;
}
var clickTime = new Date().getTime();
if( clickTime -lastClickTime < dblClickTime ) {
didDblClick = true;
setTimeout( function(){
didDblClick = false;
}, dblClickTime + 10 );
}
lastClickTime = clickTime;
setTimeout( function(){
// check if no click has since the time we called the setTimeout
if( !didDblClick ){
if( embedPlayer.paused ) {
embedPlayer.play();
} else {
embedPlayer.pause();
}
}
}, dblClickTime );
return true;
};
// Add click binding: ( $(embedPlayer).click ) has scope issues )
if ( embedPlayer.attachEvent ) {
embedPlayer.attachEvent("onclick", playerClickCb);
} else{
// Firefox 3.5 requires third argument to addEventListener
embedPlayer.addEventListener('click', playerClickCb, false );
}
},
addRightClickBinding: function(){
var embedPlayer = this.embedPlayer;
// check config:
if( mw.config.get( 'EmbedPlayer.EnableRightClick') === false ){
document.oncontextmenu= function(e){return false;};
$(embedPlayer).mousedown(function(e){
if( e.button == 2 ) {
return false;
}
});
}
},
/**
* Hide the control bar.
*/
hideControlBar : function(){
var animateDuration = 'fast';
var _this = this;
// Do not hide control bar if overlay menu item is being displayed:
if( _this.displayOptionsMenuFlag || _this.keepControlBarOnScreen ) {
setTimeout( function(){
_this.hideControlBar();
}, 200 );
return ;
}
// IE9: If the user mouse is on the control bar, don't hide it
if( this.onControlBar === true ) {
return ;
}
// Hide the control bar
this.embedPlayer.getInterface().find( '.control-bar')
.fadeOut( animateDuration );
//mw.log('about to trigger hide control bar')
// Allow interface items to update:
$( this.embedPlayer ).trigger('onHideControlBar', [ {'bottom' : 15}, this.embedPlayer.id ] );
},
restoreControlsHover:function(){
if( this.isOverlayControls() ){
this.keepControlBarOnScreen = false;
}
},
/**
* Show the control bar
*/
showControlBar: function( keepOnScreen ){
var animateDuration = 'fast';
if(! this.embedPlayer )
return ;
if( this.embedPlayer.getPlayerElement && ! this.embedPlayer.isPersistentNativePlayer() ){
$( this.embedPlayer.getPlayerElement() ).css( 'z-index', '1' );
}
mw.log( 'PlayerControlBuilder:: ShowControlBar, keep on screen: ' + keepOnScreen );
// Show interface controls
this.embedPlayer.getInterface().find( '.control-bar' )
.fadeIn( animateDuration );
if( keepOnScreen ){
this.keepControlBarOnScreen = true;
}
// Trigger the screen overlay with layout info:
$( this.embedPlayer ).trigger( 'onShowControlBar', [{
'bottom' : this.getHeight() + 15
}, this.embedPlayer.id ] );
},
/**
* Checks if the browser supports overlays and the controlsOverlay is
* set to true for the player or via config
*/
isOverlayControls: function(){
//if the player "supports" overlays:
if( ! this.embedPlayer.supports['overlays'] ){
return false;
}
// If disabled via the player
if( this.embedPlayer.overlaycontrols === false ){
return false;
}
// Don't overlay controls if in audio mode:
if( this.embedPlayer.isAudio() ){
return false;
}
// If the config is false
if( mw.config.get( 'EmbedPlayer.OverlayControls' ) === false){
return false;
}
if( this.embedPlayer.controls === false ){
return false;
}
// Past all tests OverlayControls is true:
return true;
},
/* Check if the controls are disabled */
isControlsDisabled: function() {
return this.controlsDisabled;
},
/**
* Check if a warning should be issued to non-native playback systems
*
* dependent on mediaElement being setup
*/
checkNativeWarning: function( ) {
if( mw.config.get( 'EmbedPlayer.ShowNativeWarning' ) === false ){
return false;
}
// Don't show for imageOverlay player:
if( this.embedPlayer.instanceOf == 'ImageOverlay' ){
return false;
}
// If the resolution is too small don't display the warning
if( parseInt( this.embedPlayer.getPlayerHeight() ) < 199 ){
return false;
}
// See if we have we have native support
if( this.embedPlayer.instanceOf == 'Native' ){
return false;
}
// Not a lot of good options for an iPhone
if( this.embedPlayer.instanceOf == 'VLCApp' ){
return false;
}
if( this.embedPlayer.instanceOf == 'OgvJs' ){
return false;
}
// Chrome's webM support is oky though:
if( /chrome/.test(navigator.userAgent.toLowerCase() ) &&
mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'video/webm' ).length ){
return false;
}
// Check for h264 and or flash/flv source and playback support and don't show warning
if(
( mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'video/h264' ).length
&& this.embedPlayer.mediaElement.getSources( 'video/h264' ).length )
||
( mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'video/x-flv' ).length
&& this.embedPlayer.mediaElement.getSources( 'video/x-flv' ).length )
||
( mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'application/vnd.apple.mpegurl' ).length
&& this.embedPlayer.mediaElement.getSources( 'application/vnd.apple.mpegurl' ).length )
||
( mw.EmbedTypes.getMediaPlayers().getMIMETypePlayers( 'audio/mpeg' ).length
&& this.embedPlayer.mediaElement.getSources( 'audio/mpeg' ).length )
){
// No firefox link if a h.264 or flash/flv stream is present
return false;
}
// Should issue the native warning
return true;
},
/**
* Does a native warning check binding to the player on mouse over.
* @param {string} preferenceId The preference Id
* @param {object} warningMsg The jQuery object warning message to be displayed.
*
*/
/**
* Display a warning message on the player
* checks a preference Id to enable or disable it.
* @param {string} preferenceId The preference Id
* @param {object} warningMsg The jQuery object warning message to be displayed.
* @param {boolean} if the hide ui should be exposed
*
*/
addWarningBinding: function( preferenceId, warningMsg, hideDisableUi ) {
mw.log( 'mw.PlayerControlBuilder: addWarningBinding: ' + preferenceId + ' wm: ' + warningMsg);
// Set up local pointer to the embedPlayer
var embedPlayer = this.embedPlayer;
var _this = this;
// make sure the player is large enough
if( embedPlayer.getWidth() < 200 ){
return false;
}
// Can be uncommented to reset hide prefrence
//$.cookie( preferenceId, '' );
// Check if a cookie has been set to hide the warning:
if ( mw.config.get( preferenceId ) === true && $.cookie( preferenceId ) == 'hidewarning' ){
return ;
}
var warnId = "warningOverlay_" + embedPlayer.id;
$( '#' + warnId ).remove();
// Add the targetWarning:
var $targetWarning = $('')
.attr( {
'id': warnId
} )
.addClass( 'ui-corner-all' )
.css({
'position' : 'absolute',
'background' : '#FFF',
'color' : '#111',
'top' : '10px',
'left' : '10px',
'right' : '10px',
'padding' : '4px',
// z-index should be > than play button, as well as greater
// than the dialog box (in pop up video), or link won't work.
'z-index' : '1502',
})
.html( warningMsg );
embedPlayer.getInterface().append(
$targetWarning
);
$targetWarning.append(
$(' ')
);
// check if we should show the checkbox
if( !hideDisableUi ){
$targetWarning.append(
$( '' )
.attr({
'id' : 'ffwarn_' + embedPlayer.id,
'name' : 'ffwarn_' + embedPlayer.id
})
.click( function() {
mw.log("WarningBindinng:: set " + preferenceId + ' to hidewarning ' );
// Set up a cookie for 30 days:
$.cookie( preferenceId, 'hidewarning', {expires: 30} );
// Set the current instance
mw.setConfig( preferenceId, false );
$( '#warningOverlay_' + embedPlayer.id ).fadeOut( 'slow' );
// set the local preference to false
_this.addWarningFlag = false;
} )
);
$targetWarning.append(
$('')
.text( mw.msg( 'mwe-embedplayer-do_not_warn_again' ) )
.attr( 'for', 'ffwarn_' + embedPlayer.id )
);
}
return $targetWarning;
},
/**
* Binds the volume controls
*/
doVolumeBinding: function( ) {
var embedPlayer = this.embedPlayer;
var _this = this;
embedPlayer.getInterface().find( '.volume_control' ).unbind().buttonHover().click( function() {
mw.log( 'Volume control toggle' );
embedPlayer.toggleMute();
} );
// Add vertical volume display hover
if ( this.volumeLayout == 'vertical' ) {
// Default volume binding:
var hoverOverDelay = false;
var $targetvol = embedPlayer.getInterface().find( '.vol_container' ).hide();
embedPlayer.getInterface().find( '.volume_control' ).hover(
function() {
$targetvol.addClass( 'vol_container_top' );
// Set to "below" if playing and embedType != native
if ( embedPlayer && embedPlayer.isPlaying && embedPlayer.isPlaying() && !embedPlayer.supports['overlays'] ) {
$targetvol.removeClass( 'vol_container_top' ).addClass( 'vol_container_below' );
}
$targetvol.fadeIn( 'fast' );
hoverOverDelay = true;
},
function() {
hoverOverDelay = false;
setTimeout( function() {
if ( !hoverOverDelay ) {
$targetvol.fadeOut( 'fast' );
}
}, 500 );
}
);
}
var userSlide=false;
// Setup volume slider:
var sliderConf = {
range: "min",
value: 80,
min: 0,
max: 100,
slide: function( event, ui ) {
var percent = ui.value / 100;
mw.log('PlayerControlBuilder::slide:update volume:' + percent);
embedPlayer.setVolume( percent );
userSlide = true;
},
change: function( event, ui ) {
var percent = ui.value / 100;
if ( percent == 0 ) {
embedPlayer.getInterface().find( '.volume_control span' ).removeClass( 'ui-icon-volume-on' ).addClass( 'ui-icon-volume-off' );
} else {
embedPlayer.getInterface().find( '.volume_control span' ).removeClass( 'ui-icon-volume-off' ).addClass( 'ui-icon-volume-on' );
}
mw.log('PlayerControlBuilder::change:update volume:' + percent);
embedPlayer.setVolume( percent, userSlide );
userSlide = false;
}
};
if ( this.volumeLayout == 'vertical' ) {
sliderConf[ 'orientation' ] = "vertical";
}
embedPlayer.getInterface().find( '.volume-slider' ).slider( sliderConf );
},
/**
* Get the options menu ul with li menu items
*/
getOptionsMenu: function( ) {
var $optionsMenu = $( '
' );
for( var menuItemKey in this.optionMenuItems ){
// Make sure its supported in the current controlBuilder config:
if( $.inArray( menuItemKey, mw.config.get( 'EmbedPlayer.EnabledOptionsMenuItems' ) ) === -1 ) {
continue;
}
$optionsMenu.append(
this.optionMenuItems[ menuItemKey ]( this )
);
}
return $optionsMenu;
},
/**
* Allow the controlBuilder to do interface actions onDone
*/
onClipDone: function(){
// Related videos could be shown here
},
/**
* The ctrl builder updates the interface on seeking
*/
onSeek: function(){
//mw.log( "controlBuilder:: onSeek" );
// Update the interface:
this.setStatus( mw.msg( 'mwe-embedplayer-seeking' ) );
// add a loading spinner:
this.embedPlayer.addPlayerSpinner();
// hide once playing again:
this.embedPlayer.hideSpinnerOncePlaying();
},
/**
* Updates the player status that displays short text msgs and the play clock
* @param {String} value Status string value to update
*/
setStatus: function( value ) {
// update status:
if( this.embedPlayer.getInterface() ){
this.embedPlayer.getInterface().find( '.time-disp' ).text( value );
}
},
/**
* Option menu items
*
* @return
* 'li' a li line item with click action for that menu item
*/
optionMenuItems: {
// Share the video menu
'share': function( ctrlObj ) {
return $.getLineItem(
mw.msg( 'mwe-embedplayer-share' ),
'mail-closed',
function( ) {
ctrlObj.displayMenuOverlay(
ctrlObj.getShare()
);
$( ctrlObj.embedPlayer ).trigger( 'showShareEvent' );
}
);
},
'aboutPlayerLibrary' : function( ctrlObj ){
return $.getLineItem(
mw.msg( 'mwe-embedplayer-about-library' ),
'info',
function( ) {
ctrlObj.displayMenuOverlay(
ctrlObj.aboutPlayerLibrary()
);
$( ctrlObj.embedPlayer ).trigger( 'aboutPlayerLibrary' );
}
);
}
},
/**
* Close a menu overlay
*/
closeMenuOverlay: function(){
var _this = this;
var embedPlayer = this.embedPlayer;
var $overlay = embedPlayer.getInterface().find( '.overlay-win,.ui-widget-overlay,.ui-widget-shadow' );
this.displayOptionsMenuFlag = false;
//mw.log(' closeMenuOverlay: ' + this.displayOptionsMenuFlag);
$overlay.fadeOut( "slow", function() {
$overlay.remove();
} );
// Show the big play button: ( if not in an ad .. TODO clean up )
if( embedPlayer.isStopped() &&
(
embedPlayer.sequenceProxy &&
embedPlayer.sequenceProxy.isInSequence == false
)
){
embedPlayer.getInterface().find( '.play-btn-large' ).fadeIn( 'slow' );
}
$(embedPlayer).trigger( 'closeMenuOverlay' );
return false; // onclick action return false
},
/**
* Generic function to display custom HTML overlay on video.
*
* @param {String} overlayContent content to be displayed
*/
displayMenuOverlay: function( overlayContent, closeCallback, hideCloseButton ) {
var _this = this;
var embedPlayer = this.embedPlayer;
mw.log( 'PlayerControlBuilder:: displayMenuOverlay' );
// set the overlay display flag to true:
this.displayOptionsMenuFlag = true;
if ( !this.supportedComponents[ 'overlays' ] ) {
embedPlayer.stop();
}
// Hide the big play button:
embedPlayer.hideLargePlayBtn();
// Check if overlay window is already present:
if ( embedPlayer.getInterface().find( '.overlay-win' ).length != 0 ) {
//Update the content
embedPlayer.getInterface().find( '.overlay-content' ).html(
overlayContent
);
return ;
}
// Add an overlay
embedPlayer.getInterface().append(
$('')
.addClass( 'ui-widget-overlay' )
.css( {
'height' : '100%',
'width' : '100%',
'z-index' : 2
} )
);
var $closeButton = [];
if ( !hideCloseButton ) {
// Setup the close button
$closeButton = $('')
.addClass( 'ui-state-default ui-corner-all ui-icon_link rButton')
.css({
'position': 'absolute',
'cursor' : 'pointer',
'top' : '2px',
'right' : '2px'
})
.click( function() {
_this.closeMenuOverlay();
if( closeCallback ){
closeCallback();
}
} )
.append(
$('')
.addClass( 'ui-icon ui-icon-closethick' )
);
}
var controlBarHeight = embedPlayer.getInterface().find( '.control-bar' ).height();
var overlayWidth = (embedPlayer.getWidth() - 30);
var overlayHeight = (embedPlayer.getHeight() - (controlBarHeight + 30));
var overlayTop = (( (embedPlayer.getInterface().height() - controlBarHeight) - overlayHeight) / 2);
var overlayLeft = ((embedPlayer.getInterface().width() - overlayWidth) / 2);
var overlayMenuCss = {
'height' : overlayHeight + 'px',
'width' : overlayWidth + 'px',
'position' : 'absolute',
'top' : overlayTop + 'px',
'left': overlayLeft + 'px',
'margin': '0 10px 10px 0',
'overflow' : 'auto',
'padding' : '4px',
'z-index' : 3
};
var $overlayMenu = $('')
.addClass( 'overlay-win ui-state-default ui-widget-header ui-corner-all' )
.css( overlayMenuCss )
.append(
$closeButton,
$('')
.addClass( 'overlay-content' )
.append( overlayContent )
);
// Append the overlay menu to the player interface
embedPlayer.getInterface().prepend(
$overlayMenu
)
.find( '.overlay-win' )
.fadeIn( "slow" );
// Trigger menu overlay display
$( embedPlayer ).trigger( 'displayMenuOverlay' );
return false; // onclick action return false
},
/**
* Close an alert
*/
closeAlert: function( keepOverlay ) {
var embedPlayer = this.embedPlayer;
var $alert = $( '#alertContainer' );
mw.log( 'mw.PlayerControlBuilder::closeAlert' );
if ( !keepOverlay || ( mw.isIpad() && this.inFullScreen ) ) {
embedPlayer.controlBuilder.closeMenuOverlay();
if ( mw.isIpad() ) {
embedPlayer.disablePlayControls();
}
}
$alert.remove();
return false; // onclick action return false;
},
/**
* Generic function to display custom alert overlay on video.
*
* @param (Object) Object which includes:
* title Alert Title
* body Alert body
* buttonSet[label,callback] Array of buttons
* style CSS object
*/
displayAlert: function( alertObj ) {
var embedPlayer = this.embedPlayer;
var callback;
mw.log( 'PlayerControlBuilder::displayAlert:: ' + alertObj.title );
// Check if callback is external or internal (Internal by default)
// Check if overlay window is already present:
if ( embedPlayer.getInterface().find( '.overlay-win' ).length != 0 ) {
return;
}
if( typeof alertObj.callbackFunction == 'string' ) {
if ( alertObj.isExternal ) {
// TODO better support of running external JS functions, instead of window.parent
try{
callback = window.parent[ alertObj.callbackFunction ];
} catch ( e ){
// could not call parent method
}
} else {
callback = window[ alertObj.callbackFunction ];
}
} else if( typeof alertObj.callbackFunction == 'function' ) {
// Make life easier for internal usage of the listener mapping by supporting
// passing a callback by function ref
callback = alertObj.callbackFunction;
} else {
mw.log( "PlayerControlBuilder :: displayAlert :: Error: bad callback type" );
callback = function() {};
}
var $container = $( '' ).attr( 'id', 'alertContainer' ).addClass( 'alert-container' );
var $title = $( '' ).text( alertObj.title ).addClass( 'alert-title alert-text' );
if ( alertObj.props && alertObj.props.titleTextColor ) {
$title.removeClass( 'alert-text' );
$title.css( 'color', mw.getHexColor( alertObj.props.titleTextColor ) );
}
var $message = $( '' ).text( alertObj.message ).addClass( 'alert-message alert-text' );
if ( alertObj.isError ) {
$message.addClass( 'error' );
}
if ( alertObj.props && alertObj.props.textColor ) {
$message.removeClass( 'alert-text' );
$message.css( 'color', mw.getHexColor( alertObj.props.textColor ) );
}
var $buttonsContainer = $( '' ).addClass( 'alert-buttons-container' );
if ( alertObj.props && alertObj.props.buttonRowSpacing ) {
$buttonsContainer.css( 'margin-top', alertObj.props.buttonRowSpacing );
}
var $buttonSet = alertObj.buttons || [];
// If no button was passed display just OK button
var buttonsNum = $buttonSet.length;
if ( buttonsNum == 0 && !alertObj.noButtons ) {
$buttonSet = ["OK"];
buttonsNum++;
}
$.each( $buttonSet, function(i) {
var label = this.toString();
var $currentButton = $( '' )
.addClass( 'alert-button' )
.text( label )
.click( function( eventObject ) {
callback( eventObject );
embedPlayer.controlBuilder.closeAlert( alertObj.keepOverlay );
} );
if ( alertObj.props && alertObj.props.buttonHeight ) {
$currentButton.css( 'height', alertObj.props.buttonHeight );
}
// Apply buttons spacing only when more than one is present
if (buttonsNum > 1) {
if (i < buttonsNum-1) {
if ( alertObj.props && alertObj.props.buttonSpacing ) {
$currentButton.css( 'margin-right', alertObj.props.buttonSpacing );
}
}
}
$buttonsContainer.append( $currentButton );
} )
$container.append( $title, $message, $buttonsContainer );
return embedPlayer.controlBuilder.displayMenuOverlay( $container, false, true );
},
aboutPlayerLibrary: function(){
return $( '' )
.append(
$( '' )
.text(
mw.msg('mwe-embedplayer-about-library')
)
,
$( '')
.append(
mw.msg('mwe-embedplayer-about-library-desc',
$('
').append(
$('').attr({
'href' : mw.config.get( 'EmbedPlayer.LibraryPage' ),
'target' : '_new'
})
)[0].innerHTML
)
)
);
},
/**
* Get the "share" interface
*
* TODO share should be enabled via