wait for in-slide video/audio to load before playing, reuse same autoplay logic for slide backgrounds
This commit is contained in:
		
							
								
								
									
										76
									
								
								js/reveal.js
									
									
									
									
									
								
							
							
						
						
									
										76
									
								
								js/reveal.js
									
									
									
									
									
								
							| @@ -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' ); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user