diff options
Diffstat (limited to 'extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.processEmbedPlayers.js')
-rw-r--r-- | extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.processEmbedPlayers.js | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.processEmbedPlayers.js b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.processEmbedPlayers.js new file mode 100644 index 00000000..0748ccd0 --- /dev/null +++ b/extensions/TimedMediaHandler/MwEmbedModules/EmbedPlayer/resources/mw.processEmbedPlayers.js @@ -0,0 +1,353 @@ +/** + * Selector based embedPlayer processing + * + * @param {Function=} + * callback Optional Function to be called once video interfaces + * are ready + * + */ + +( function( mw, $ ) { "use strict"; + +mw.processEmbedPlayers = function( playerSet, callback ) { + mw.log( 'processEmbedPlayers:: playerSet: ', playerSet); + // The player id list container + var playerIdList = []; + + // Check if the selected player set is ready if ready issue the parent callback + var areSelectedPlayersReady = function(){ + var playersLoaded = true; + $.each( playerIdList, function(inx, playerId){ + if( ! $( '#' + playerId )[0].playerReadyFlag ){ + playersLoaded = false; + return false; + } + }) + if( playersLoaded ){ + if( callback ){ + callback(); + } + } + } + + /** + * Adds a player element for the embedPlayer to rewrite + * + * uses embedPlayer interface on audio / video elements uses mvPlayList + * interface on playlist elements + * + * Once a player interface is established the following chain of functions + * are called; + * + * _this.checkPlayerSources() + * _this.setupSourcePlayer() + * _this.updatePlaybackInterface() + * _this.selectedPlayer.load() + * _this.showPlayer() + * + * @param {Element} + * playerElement DOM element to be swapped + */ + var addPlayerElement = function( playerElement ) { + var _this = this; + mw.log('EmbedPlayer:: addElement:: ' + playerElement.id ); + + // Be sure to "stop" the target ( Firefox 3x keeps playing + // the video even though its been removed from the DOM ) + if( playerElement.pause ){ + playerElement.pause(); + } + + // Allow modules to override the wait for metadata flag: + $( mw ).trigger( 'EmbedPlayerWaitForMetaCheck', playerElement ); + + // DOM *could* load height, width and duration eventually, in some browsers + // By default, don't bother waiting for this. + var waitForMeta = false; + + // if a plugin has told us not to waitForMeta, don't + if ( playerElement.waitForMeta !== false ) { + // Check if we should wait for metadata, after all + waitForMeta = waitForMetaCheck( playerElement ); + } + + var ranPlayerSwapFlag = false; + + // Local callback to runPlayer swap once playerElement has metadata + var runPlayerSwap = function () { + // Don't run player swap twice + if( ranPlayerSwapFlag ){ + return ; + } + ranPlayerSwapFlag = true; + mw.log( "processEmbedPlayers::runPlayerSwap::" + $( playerElement ).attr('id') ); + + var playerInterface = new mw.EmbedPlayer( playerElement ); + var inDomPlayer = swapEmbedPlayerElement( playerElement, playerInterface ); + + // IE/Edge with WebM components re-triggers autoplay after removal as well. + if( playerElement.pause ){ + playerElement.pause(); + } + + // Trigger the EmbedPlayerNewPlayer for embedPlayer interface + mw.log("processEmbedPlayers::trigger:: EmbedPlayerNewPlayer " + inDomPlayer.id ); + + // Allow plugins to add bindings to the inDomPlayer + $( mw ).trigger ( 'EmbedPlayerNewPlayer', inDomPlayer ); + + // Add a player ready binding: + $( inDomPlayer ).bind( 'playerReady.swap', function(event, id){ + $( inDomPlayer ).unbind( 'playerReady.swap' ); + areSelectedPlayersReady(); + }); + + // + // Allow modules to block player build out + // + // this is needed in cases where you need to do an asynchronous + // player interface setup. like iframes asynchronous announcing its ready for + // bindings that can affect player setup. + mw.log("EmbedPlayer::addPlayerElement :trigger startPlayerBuildOut:" + inDomPlayer.id ); + $( '#' + inDomPlayer.id ).triggerQueueCallback( 'startPlayerBuildOut', function(){ + // Issue the checkPlayerSources call to the new player + // interface: make sure to use the element that is in the DOM: + inDomPlayer.checkPlayerSources(); + }); + }; + + if( waitForMeta && mw.config.get('EmbedPlayer.WaitForMeta' ) ) { + mw.log('processEmbedPlayers::WaitForMeta ( video missing height (' + + $( playerElement ).attr('height') + '), width (' + + $( playerElement ).attr('width') + ') or duration: ' + + $( playerElement ).attr('duration') + ); + $( playerElement ).bind( "loadedmetadata", runPlayerSwap ); + + // Time-out of 5 seconds ( maybe still playable but no timely metadata ) + setTimeout( runPlayerSwap, 5000 ); + return ; + } else { + runPlayerSwap(); + return ; + } + }; + + /** + * Check if we should wait for metadata. + * + * @return true if the size is "likely" to be updated by waiting for metadata + * false if the size has been set via an attribute or is already loaded + */ + var waitForMetaCheck = function( playerElement ){ + var waitForMeta = false; + + // Don't wait for metadata for non html5 media elements + if( !playerElement ){ + return false; + } + if( !playerElement.tagName || ( playerElement.tagName.toLowerCase() != 'audio' && playerElement.tagName.toLowerCase() != 'video' ) ){ + return false; + } + // If we don't have a native player don't wait for metadata + if( !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'oggNative') && + !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'webmNative') && + !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'h264Native' ) && + !mw.EmbedTypes.getMediaPlayers().isSupportedPlayer( 'appleVdnPlayer' ) ) + { + return false; + } + + + var width = $( playerElement ).css( 'width' ); + var height = $( playerElement ).css( 'height' ); + // Css video defaults ( firefox ) + if( $( playerElement ).css( 'width' ) == '300px' && + $( playerElement ).css( 'height' ) == '150px' + ){ + waitForMeta = true; + } else { + // Check if we should wait for duration: + if( $( playerElement ).attr( 'duration') || + $( playerElement ).attr( 'durationHint') || + $( playerElement ).attr('data-durationhint') + ){ + // height, width and duration set; do not wait for meta data: + return false; + } else { + waitForMeta = true; + } + } + + // Firefox ~ sometimes~ gives -1 for unloaded media + if ( $(playerElement).attr( 'width' ) == -1 || $(playerElement).attr( 'height' ) == -1 ) { + waitForMeta = true; + } + + // Google Chrome / safari gives 0 width height for unloaded media + if( $(playerElement).attr( 'width' ) === 0 || + $(playerElement).attr( 'height' ) === 0 + ) { + waitForMeta = true; + } + + // Firefox default width height is ~sometimes~ 150 / 300 + if( playerElement.height == 150 && playerElement.width == 300 ){ + waitForMeta = true; + } + + // Make sure we have a src attribute or source child + // ( i.e not a video tag to be dynamically populated or looked up from + // xml resource description ) + if( waitForMeta && + ( + $( playerElement ).attr('src') || + $( playerElement ).find("source[src]").length !== 0 + ) + ) { + // Detect src type ( if no type set ) + return true; + } else { + // playerElement is not likely to update its meta data ( no src ) + return false; + } + }; + + /** + * swapEmbedPlayerElement + * + * Takes a video element as input and swaps it out with an embed player interface + * + * @param {Element} + * targetElement Element to be swapped + * @param {Object} + * playerInterface Interface to swap into the target element + */ + var swapEmbedPlayerElement = function( targetElement, playerInterface ) { + mw.log( 'processEmbedPlayers::swapEmbedPlayerElement: ' + targetElement.id ); + // Create a new element to swap the player interface into + var swapPlayerElement = document.createElement('div'); + + // Add a class that identifies all embedPlayers: + $( swapPlayerElement ).addClass( 'mwEmbedPlayer' ); + + // Get properties / methods from playerInterface: + for ( var method in playerInterface ) { + if ( method != 'readyState' ) { // readyState crashes IE ( don't include ) + swapPlayerElement[ method ] = playerInterface[ method ]; + } + } + // copy over css text: + swapPlayerElement.style.cssText = targetElement.style.cssText; + // player element must always be relative to host video and image layout + swapPlayerElement.style.position = 'relative'; + + // Copy any data attributes from the target player element over to the swapPlayerElement + var dataAttributes = mw.config.get("EmbedPlayer.DataAttributes"); + if( dataAttributes ){ + $.each( dataAttributes, function( attrName, na ){ + if( $( targetElement ).data( attrName ) ){ + $( swapPlayerElement ).data( attrName, $( targetElement ).data( attrName ) ); + } + }); + } + // Check for Persistent native player ( should keep the video embed around ) + if( playerInterface.isPersistentNativePlayer() + || + // Also check for native controls on a video or audio tag + ( playerInterface.useNativePlayerControls() + && + ( targetElement.nodeName == 'video' || targetElement.nodeName == 'audio' ) + ) + ) { + + $( targetElement ) + .attr( 'id', playerInterface.pid ) + .addClass( 'nativeEmbedPlayerPid' ) + .show() + .after( + $( swapPlayerElement ).css( 'display', 'none' ) + ); + + } else { + $( targetElement ).replaceWith( swapPlayerElement ); + } + + // If we don't already have a loadSpiner add one: + if( $('#loadingSpinner_' + playerInterface.id ).length == 0 && $.client.profile().name !== 'firefox' ){ + if( playerInterface.useNativePlayerControls() || playerInterface.isPersistentNativePlayer() ) { + var $spinner = $( targetElement ) + .getAbsoluteOverlaySpinner(); + }else{ + var $spinner = $( swapPlayerElement ).getAbsoluteOverlaySpinner(); + } + $spinner.attr('id', 'loadingSpinner_' + playerInterface.id ); + } + return swapPlayerElement; + }; + + // Add a loader for <div /> embed player rewrites: + $( playerSet ).each( function( index, playerElement) { + + // Make sure the playerElement has an id: + if( !$( playerElement ).attr('id') ){ + $( playerElement ).attr( "id", 'mwe_vid' + ( index ) ); + } + // Add the player Id to the playerIdList + playerIdList.push( $( playerElement ).attr( "id") ); + + // If we are dynamically embedding on a "div" check if we can + // add a poster image behind the loader: + if( playerElement.nodeName.toLowerCase() == 'div' + && + $(playerElement).attr( 'poster' ) ) + { + var posterSrc = $(playerElement).attr( 'poster' ); + + // Set image size: + var width = $( playerElement ).width(); + var height = $( playerElement ).height(); + if( !width ){ + var width = '100%'; + } + if( !height ){ + var height = '100%'; + } + + mw.log('EmbedPlayer:: set loading background: ' + posterSrc); + $( playerElement ).append( + $( '<img />' ) + .attr( 'src', posterSrc) + .css({ + 'position' : 'absolute', + 'width' : width, + 'height' : height + }) + ); + } + }); + + // Make sure we have user preference setup for setting preferences on video selection + var addedPlayersFlag = false; + mw.log("processEmbedPlayers:: Do: " + $( playerSet ).length + ' players '); + // Add each selected element to the player manager: + $( playerSet ).each( function( index, playerElement) { + // Make sure the video tag was not generated by our library: + if( $( playerElement ).hasClass( 'nativeEmbedPlayerPid' ) ){ + $( '#loadingSpinner_' + $( playerElement ).attr('id') ).remove(); + mw.log( 'processEmbedPlayers::$.embedPlayer skip embedPlayer gennerated video: ' + playerElement ); + } else { + addedPlayersFlag = true; + // Add the player + addPlayerElement( playerElement ); + } + }); + if( !addedPlayersFlag ){ + // Run the callback directly if no players were added + if( callback ){ + callback(); + } + } +}; + +})( mw, jQuery ); |