wait for in-slide video/audio to load before playing, reuse same autoplay logic for slide backgrounds

This commit is contained in:
Hakim El Hattab 2017-01-16 16:11:20 +01:00
parent 568c7516f7
commit a38207f1d7
1 changed files with 43 additions and 35 deletions

View File

@ -2873,34 +2873,17 @@
} ); } );
// Stop any currently playing video background // Stop content inside of previous backgrounds
if( previousBackground ) { if( previousBackground ) {
var previousVideo = previousBackground.querySelector( 'video' ); stopEmbeddedContent( previousBackground );
if( previousVideo ) previousVideo.pause();
} }
// Start content in the current background
if( currentBackground ) { if( currentBackground ) {
// Start video playback startEmbeddedContent( currentBackground, true );
var currentVideo = currentBackground.querySelector( 'video' );
if( currentVideo ) {
var startVideo = function() {
currentVideo.currentTime = 0;
currentVideo.play();
currentVideo.removeEventListener( 'loadeddata', startVideo );
};
if( currentVideo.readyState > 1 ) {
startVideo();
}
else {
currentVideo.addEventListener( 'loadeddata', startVideo );
}
}
var backgroundImageURL = currentBackground.style.backgroundImage || ''; var backgroundImageURL = currentBackground.style.backgroundImage || '';
@ -3189,11 +3172,12 @@
* Start playback of any embedded content inside of * Start playback of any embedded content inside of
* the given element. * the given element.
* *
* @param {HTMLElement} slide * @param {HTMLElement} element
*/ */
function startEmbeddedContent( element ) { function startEmbeddedContent( element ) {
if( element && !isSpeakerNotes() ) { if( element && !isSpeakerNotes() ) {
// Restart GIFs // Restart GIFs
toArray( element.querySelectorAll( 'img[src$=".gif"]' ) ).forEach( function( el ) { toArray( element.querySelectorAll( 'img[src$=".gif"]' ) ).forEach( function( el ) {
// Setting the same unchanged source like this was confirmed // Setting the same unchanged source like this was confirmed
@ -3207,8 +3191,27 @@
return; return;
} }
if( el.hasAttribute( 'data-autoplay' ) && typeof el.play === 'function' ) { // Autoplay is always on for slide backgrounds
el.play(); var autoplay = el.hasAttribute( 'data-autoplay' ) || !!closestParent( el, '.slide-background' );
if( autoplay && typeof el.play === 'function' ) {
var _startVideo = function() {
// Only start playback if the containing slide is still visible
if( !!closestParent( el, '.present' ) ) {
el.currentTime = 0;
el.play();
}
el.removeEventListener( 'loadeddata', _startVideo );
};
if( el.readyState > 1 ) {
_startVideo();
}
else {
el.addEventListener( 'loadeddata', _startVideo );
}
} }
} ); } );
@ -3233,6 +3236,7 @@
el.setAttribute( 'src', el.getAttribute( 'data-src' ) ); el.setAttribute( 'src', el.getAttribute( 'data-src' ) );
} }
} ); } );
} }
} }
@ -3249,12 +3253,14 @@
if( iframe && iframe.contentWindow ) { if( iframe && iframe.contentWindow ) {
var autoplay = iframe.hasAttribute( 'data-autoplay' ) || !!closestParent( iframe, '.slide-background' );
// YouTube postMessage API // YouTube postMessage API
if( /youtube\.com\/embed\//.test( iframe.getAttribute( 'src' ) ) && iframe.hasAttribute( 'data-autoplay' ) ) { if( /youtube\.com\/embed\//.test( iframe.getAttribute( 'src' ) ) && autoplay ) {
iframe.contentWindow.postMessage( '{"event":"command","func":"playVideo","args":""}', '*' ); iframe.contentWindow.postMessage( '{"event":"command","func":"playVideo","args":""}', '*' );
} }
// Vimeo postMessage API // Vimeo postMessage API
else if( /player\.vimeo\.com\//.test( iframe.getAttribute( 'src' ) ) && iframe.hasAttribute( 'data-autoplay' ) ) { else if( /player\.vimeo\.com\//.test( iframe.getAttribute( 'src' ) ) && autoplay ) {
iframe.contentWindow.postMessage( '{"method":"play"}', '*' ); iframe.contentWindow.postMessage( '{"method":"play"}', '*' );
} }
// Generic postMessage API // Generic postMessage API
@ -3270,40 +3276,42 @@
* Stop playback of any embedded content inside of * Stop playback of any embedded content inside of
* the targeted slide. * the targeted slide.
* *
* @param {HTMLElement} slide * @param {HTMLElement} element
* @param {boolean} autoplay Optionally override the
* autoplay setting of media elements
*/ */
function stopEmbeddedContent( slide ) { function stopEmbeddedContent( element, autoplay ) {
if( slide && slide.parentNode ) { if( element && element.parentNode ) {
// HTML5 media elements // HTML5 media elements
toArray( slide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) { toArray( element.querySelectorAll( 'video, audio' ) ).forEach( function( el ) {
if( !el.hasAttribute( 'data-ignore' ) && typeof el.pause === 'function' ) { if( !el.hasAttribute( 'data-ignore' ) && typeof el.pause === 'function' ) {
el.pause(); el.pause();
} }
} ); } );
// Generic postMessage API for non-lazy loaded iframes // Generic postMessage API for non-lazy loaded iframes
toArray( slide.querySelectorAll( 'iframe' ) ).forEach( function( el ) { toArray( element.querySelectorAll( 'iframe' ) ).forEach( function( el ) {
el.contentWindow.postMessage( 'slide:stop', '*' ); el.contentWindow.postMessage( 'slide:stop', '*' );
el.removeEventListener( 'load', startEmbeddedIframe ); el.removeEventListener( 'load', startEmbeddedIframe );
}); });
// YouTube postMessage API // YouTube postMessage API
toArray( slide.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( function( el ) { toArray( element.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( function( el ) {
if( !el.hasAttribute( 'data-ignore' ) && typeof el.contentWindow.postMessage === 'function' ) { if( !el.hasAttribute( 'data-ignore' ) && typeof el.contentWindow.postMessage === 'function' ) {
el.contentWindow.postMessage( '{"event":"command","func":"pauseVideo","args":""}', '*' ); el.contentWindow.postMessage( '{"event":"command","func":"pauseVideo","args":""}', '*' );
} }
}); });
// Vimeo postMessage API // Vimeo postMessage API
toArray( slide.querySelectorAll( 'iframe[src*="player.vimeo.com/"]' ) ).forEach( function( el ) { toArray( element.querySelectorAll( 'iframe[src*="player.vimeo.com/"]' ) ).forEach( function( el ) {
if( !el.hasAttribute( 'data-ignore' ) && typeof el.contentWindow.postMessage === 'function' ) { if( !el.hasAttribute( 'data-ignore' ) && typeof el.contentWindow.postMessage === 'function' ) {
el.contentWindow.postMessage( '{"method":"pause"}', '*' ); el.contentWindow.postMessage( '{"method":"pause"}', '*' );
} }
}); });
// Lazy loading iframes // Lazy loading iframes
toArray( slide.querySelectorAll( 'iframe[data-src]' ) ).forEach( function( el ) { toArray( element.querySelectorAll( 'iframe[data-src]' ) ).forEach( function( el ) {
// Only removing the src doesn't actually unload the frame // Only removing the src doesn't actually unload the frame
// in all browsers (Firefox) so we set it to blank first // in all browsers (Firefox) so we set it to blank first
el.setAttribute( 'src', 'about:blank' ); el.setAttribute( 'src', 'about:blank' );
@ -3900,7 +3908,7 @@
// If there are media elements with data-autoplay, // If there are media elements with data-autoplay,
// automatically set the autoSlide duration to the // automatically set the autoSlide duration to the
// length of that media. Not applicable if the slide // length of that media. Not applicable if the slide
// is divided up into fragments. // is divided up into fragments.
// playbackRate is accounted for in the duration. // playbackRate is accounted for in the duration.
if( currentSlide.querySelectorAll( '.fragment' ).length === 0 ) { if( currentSlide.querySelectorAll( '.fragment' ).length === 0 ) {
toArray( currentSlide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) { toArray( currentSlide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) {