lib/resources/assets/revealjs-redhat/lib/js/debug/reveal.js in hyla-1.0.7 vs lib/resources/assets/revealjs-redhat/lib/js/debug/reveal.js in hyla-1.0.8

- old
+ new

@@ -1,9 +1,10 @@ /*! * reveal.js * http://lab.hakim.se/reveal-js * MIT licensed + * Version 3.1.0 * * Copyright (C) 2015 Hakim El Hattab, http://hakim.se */ (function( root, factory ) { if( typeof define === 'function' && define.amd ) { @@ -28,25 +29,21 @@ var SLIDES_SELECTOR = '.slides section', HORIZONTAL_SLIDES_SELECTOR = '.slides>section', VERTICAL_SLIDES_SELECTOR = '.slides>section.present>section', HOME_SLIDE_SELECTOR = '.slides>section:first-of-type', - // Configurations defaults, can be overridden at initialization time + // Configuration defaults, can be overridden at initialization time config = { // The "normal" size of the presentation, aspect ratio will be preserved // when the presentation is scaled to fit different resolutions width: 960, height: 700, // Factor of the display size that should remain empty around the content margin: 0.1, - // Top and Left margins to reposition the slides - marginTop: '', - marginLeft: '', - // Bounds for smallest/largest possible scale to apply to content minScale: 0.2, maxScale: 1.5, // Display controls in the bottom right corner @@ -240,18 +237,22 @@ checkCapabilities(); if( !features.transforms2d && !features.transforms3d ) { document.body.setAttribute( 'class', 'no-transforms' ); - // Since JS won't be running any further, we need to load all - // images that were intended to lazy load now - var images = document.getElementsByTagName( 'img' ); - for( var i = 0, len = images.length; i < len; i++ ) { - var image = images[i]; - if( image.getAttribute( 'data-src' ) ) { - image.setAttribute( 'src', image.getAttribute( 'data-src' ) ); - image.removeAttribute( 'data-src' ); + // Since JS won't be running any further, we load all lazy + // loading elements upfront + var images = toArray( document.getElementsByTagName( 'img' ) ), + iframes = toArray( document.getElementsByTagName( 'iframe' ) ); + + var lazyLoadable = images.concat( iframes ); + + for( var i = 0, len = lazyLoadable.length; i < len; i++ ) { + var element = lazyLoadable[i]; + if( element.getAttribute( 'data-src' ) ) { + element.setAttribute( 'src', element.getAttribute( 'data-src' ) ); + element.removeAttribute( 'data-src' ); } } // If the browser doesn't support core features we won't be // using JavaScript to control the presentation @@ -288,20 +289,20 @@ * should only happens once per runtime. */ function checkCapabilities() { features.transforms3d = 'WebkitPerspective' in document.body.style || - 'MozPerspective' in document.body.style || - 'msPerspective' in document.body.style || - 'OPerspective' in document.body.style || - 'perspective' in document.body.style; + 'MozPerspective' in document.body.style || + 'msPerspective' in document.body.style || + 'OPerspective' in document.body.style || + 'perspective' in document.body.style; features.transforms2d = 'WebkitTransform' in document.body.style || - 'MozTransform' in document.body.style || - 'msTransform' in document.body.style || - 'OTransform' in document.body.style || - 'transform' in document.body.style; + 'MozTransform' in document.body.style || + 'msTransform' in document.body.style || + 'OTransform' in document.body.style || + 'transform' in document.body.style; features.requestAnimationFrameMethod = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; features.requestAnimationFrame = typeof features.requestAnimationFrameMethod === 'function'; features.canvas = !!document.createElement( 'canvas' ).getContext; @@ -733,18 +734,18 @@ // Create a hash for this combination of background settings. // This is used to determine when two slide backgrounds are // the same. if( data.background || data.backgroundColor || data.backgroundImage || data.backgroundVideo || data.backgroundIframe ) { element.setAttribute( 'data-background-hash', data.background + - data.backgroundSize + - data.backgroundImage + - data.backgroundVideo + - data.backgroundIframe + - data.backgroundColor + - data.backgroundRepeat + - data.backgroundPosition + - data.backgroundTransition ); + data.backgroundSize + + data.backgroundImage + + data.backgroundVideo + + data.backgroundIframe + + data.backgroundColor + + data.backgroundRepeat + + data.backgroundPosition + + data.backgroundTransition ); } // Additional and optional background properties if( data.backgroundSize ) element.style.backgroundSize = data.backgroundSize; if( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor; @@ -1134,11 +1135,11 @@ document.getElementsByTagName( 'head' )[0].appendChild( tag ); } /** - * Measures the distance in pixels between point a and point b. + * Converts various color input formats to an {r:0,g:0,b:0} object. * * @param {String} color The string representation of a color, * the following formats are supported: * - #000 * - #000000 @@ -1531,25 +1532,19 @@ } else { // Prefer zooming in desktop Chrome so that content remains crisp if( !isMobileDevice && /chrome/i.test( navigator.userAgent ) && typeof dom.slides.style.zoom !== 'undefined' ) { dom.slides.style.zoom = scale; - dom.slides.style.marginTop = config.marginTop; - dom.slides.style.marginLeft = config.marginLeft; transformSlides( { layout: '' } ); } // Apply scale transform as a fallback else { - // dom.slides.style.left = '50%'; - // dom.slides.style.top = '44%'; - // dom.slides.style.bottom = 'auto'; - // dom.slides.style.right = 'auto'; - dom.slides.style.marginTop = config.marginTop; - dom.slides.style.marginLeft = config.marginLeft; - dom.slides.style.marginBottom = 'auto'; - dom.slides.style.marginRight = 'auto'; - transformSlides( { layout: 'translate(-50%, -50%) scale('+ scale +') translate(50%, 50%)' } ); + dom.slides.style.left = '50%'; + dom.slides.style.top = '50%'; + dom.slides.style.bottom = 'auto'; + dom.slides.style.right = 'auto'; + transformSlides( { layout: 'translate(-50%, -50%) scale('+ scale +')' } ); } } // Select all slides, vertical and horizontal var slides = toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) ); @@ -1633,11 +1628,11 @@ presentationWidth: presentationWidth || dom.wrapper.offsetWidth, presentationHeight: presentationHeight || dom.wrapper.offsetHeight }; // Reduce available space by margin - size.presentationWidth -= ( size.presentationHeight * config.margin ); + size.presentationWidth -= ( size.presentationWidth * config.margin ); size.presentationHeight -= ( size.presentationHeight * config.margin ); // Slide width may be a percentage of available width if( typeof size.width === 'string' && /%$/.test( size.width ) ) { size.width = parseInt( size.width, 10 ) / 100 * size.presentationWidth; @@ -2201,10 +2196,11 @@ updateBackground( true ); updateSlideNumber(); updateSlidesVisibility(); formatEmbeddedContent(); + startEmbeddedContent( currentSlide ); if( isOverview() ) { layoutOverview(); } @@ -2483,16 +2479,14 @@ // Check if a custom slide number format is available if( typeof config.slideNumber === 'string' ) { format = config.slideNumber; } - var totalSlides = getTotalSlides(); - dom.slideNumber.innerHTML = format.replace( /h/g, indexh ) .replace( /v/g, indexv ) - .replace( /c/g, Math.round( getProgress() * totalSlides ) + 1 ) - .replace( /t/g, totalSlides + 1 ); + .replace( /c/g, getSlidePastCount() + 1 ) + .replace( /t/g, getTotalSlides() ); } } /** @@ -2729,11 +2723,11 @@ // Show the slide element slide.style.display = 'block'; // Media elements with data-src attributes - toArray( slide.querySelectorAll( 'img[data-src], video[data-src], audio[data-src], iframe[data-src]' ) ).forEach( function( element ) { + toArray( slide.querySelectorAll( 'img[data-src], video[data-src], audio[data-src]' ) ).forEach( function( element ) { element.setAttribute( 'src', element.getAttribute( 'data-src' ) ); element.removeAttribute( 'data-src' ); } ); // Media elements with <source> children @@ -2876,25 +2870,26 @@ /** * Enforces origin-specific format rules for embedded media. */ function formatEmbeddedContent() { + var _appendParamToIframeSource = function( sourceAttribute, sourceURL, param ) { + toArray( dom.slides.querySelectorAll( 'iframe['+ sourceAttribute +'*="'+ sourceURL +'"]' ) ).forEach( function( el ) { + var src = el.getAttribute( sourceAttribute ); + if( src && src.indexOf( param ) === -1 ) { + el.setAttribute( sourceAttribute, src + ( !/\?/.test( src ) ? '?' : '&' ) + param ); + } + }); + }; + // YouTube frames must include "?enablejsapi=1" - toArray( dom.slides.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( function( el ) { - var src = el.getAttribute( 'src' ); - if( !/enablejsapi\=1/gi.test( src ) ) { - el.setAttribute( 'src', src + ( !/\?/.test( src ) ? '?' : '&' ) + 'enablejsapi=1' ); - } - }); + _appendParamToIframeSource( 'src', 'youtube.com/embed/', 'enablejsapi=1' ); + _appendParamToIframeSource( 'data-src', 'youtube.com/embed/', 'enablejsapi=1' ); // Vimeo frames must include "?api=1" - toArray( dom.slides.querySelectorAll( 'iframe[src*="player.vimeo.com/"]' ) ).forEach( function( el ) { - var src = el.getAttribute( 'src' ); - if( !/api\=1/gi.test( src ) ) { - el.setAttribute( 'src', src + ( !/\?/.test( src ) ? '?' : '&' ) + 'api=1' ); - } - }); + _appendParamToIframeSource( 'src', 'player.vimeo.com/', 'api=1' ); + _appendParamToIframeSource( 'data-src', 'player.vimeo.com/', 'api=1' ); } /** * Start playback of any embedded content inside of @@ -2910,34 +2905,52 @@ el.setAttribute( 'src', el.getAttribute( 'src' ) ); } ); // HTML5 media elements toArray( slide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) { - if( el.hasAttribute( 'data-autoplay' ) ) { + if( el.hasAttribute( 'data-autoplay' ) && typeof el.play === 'function' ) { el.play(); } } ); - // iframe embeds - toArray( slide.querySelectorAll( 'iframe' ) ).forEach( function( el ) { - el.contentWindow.postMessage( 'slide:start', '*' ); - }); + // Normal iframes + toArray( slide.querySelectorAll( 'iframe[src]' ) ).forEach( function( el ) { + startEmbeddedIframe( { target: el } ); + } ); - // YouTube embeds - toArray( slide.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( function( el ) { - if( el.hasAttribute( 'data-autoplay' ) ) { - el.contentWindow.postMessage( '{"event":"command","func":"playVideo","args":""}', '*' ); + // Lazy loading iframes + toArray( slide.querySelectorAll( 'iframe[data-src]' ) ).forEach( function( el ) { + if( el.getAttribute( 'src' ) !== el.getAttribute( 'data-src' ) ) { + el.removeEventListener( 'load', startEmbeddedIframe ); // remove first to avoid dupes + el.addEventListener( 'load', startEmbeddedIframe ); + el.setAttribute( 'src', el.getAttribute( 'data-src' ) ); } - }); + } ); + } - // Vimeo embeds - toArray( slide.querySelectorAll( 'iframe[src*="player.vimeo.com/"]' ) ).forEach( function( el ) { - if( el.hasAttribute( 'data-autoplay' ) ) { - el.contentWindow.postMessage( '{"method":"play"}', '*' ); - } - }); + } + + /** + * "Starts" the content of an embedded iframe using the + * postmessage API. + */ + function startEmbeddedIframe( event ) { + + var iframe = event.target; + + // YouTube postMessage API + if( /youtube\.com\/embed\//.test( iframe.getAttribute( 'src' ) ) && iframe.hasAttribute( 'data-autoplay' ) ) { + iframe.contentWindow.postMessage( '{"event":"command","func":"playVideo","args":""}', '*' ); } + // Vimeo postMessage API + else if( /player\.vimeo\.com\//.test( iframe.getAttribute( 'src' ) ) && iframe.hasAttribute( 'data-autoplay' ) ) { + iframe.contentWindow.postMessage( '{"method":"play"}', '*' ); + } + // Generic postMessage API + else { + iframe.contentWindow.postMessage( 'slide:start', '*' ); + } } /** * Stop playback of any embedded content inside of @@ -2946,47 +2959,55 @@ function stopEmbeddedContent( slide ) { if( slide && slide.parentNode ) { // HTML5 media elements toArray( slide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) { - if( !el.hasAttribute( 'data-ignore' ) ) { + if( !el.hasAttribute( 'data-ignore' ) && typeof el.pause === 'function' ) { el.pause(); } } ); - // iframe embeds + // Generic postMessage API for non-lazy loaded iframes toArray( slide.querySelectorAll( 'iframe' ) ).forEach( function( el ) { el.contentWindow.postMessage( 'slide:stop', '*' ); + el.removeEventListener( 'load', startEmbeddedIframe ); }); - // YouTube embeds + // YouTube postMessage API toArray( slide.querySelectorAll( 'iframe[src*="youtube.com/embed/"]' ) ).forEach( function( el ) { if( !el.hasAttribute( 'data-ignore' ) && typeof el.contentWindow.postMessage === 'function' ) { el.contentWindow.postMessage( '{"event":"command","func":"pauseVideo","args":""}', '*' ); } }); - // Vimeo embeds + // Vimeo postMessage API toArray( slide.querySelectorAll( 'iframe[src*="player.vimeo.com/"]' ) ).forEach( function( el ) { if( !el.hasAttribute( 'data-ignore' ) && typeof el.contentWindow.postMessage === 'function' ) { el.contentWindow.postMessage( '{"method":"pause"}', '*' ); } }); + + // Lazy loading iframes + toArray( slide.querySelectorAll( 'iframe[data-src]' ) ).forEach( function( el ) { + // Only removing the src doesn't actually unload the frame + // in all browsers (Firefox) so we set it to blank first + el.setAttribute( 'src', 'about:blank' ); + el.removeAttribute( 'src' ); + } ); } } /** - * Returns a value ranging from 0-1 that represents - * how far into the presentation we have navigated. + * Returns the number of past slides. This can be used as a global + * flattened index for slides. */ - function getProgress() { + function getSlidePastCount() { var horizontalSlides = toArray( dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ); - // The number of past and total slides - var totalCount = getTotalSlides(); + // The number of past slides var pastCount = 0; // Step through all slides and count the past ones mainLoop: for( var i = 0; i < horizontalSlides.length; i++ ) { @@ -3014,10 +3035,24 @@ pastCount++; } } + return pastCount; + + } + + /** + * Returns a value ranging from 0-1 that represents + * how far into the presentation we have navigated. + */ + function getProgress() { + + // The number of past and total slides + var totalCount = getTotalSlides(); + var pastCount = getSlidePastCount(); + if( currentSlide ) { var allFragments = currentSlide.querySelectorAll( '.fragment' ); // If there are fragments in the current slide those should be @@ -3498,17 +3533,20 @@ autoSlide = config.autoSlide; } // If there are media elements with data-autoplay, // automatically set the autoSlide duration to the - // length of that media - toArray( currentSlide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) { - if( el.hasAttribute( 'data-autoplay' ) ) { - if( autoSlide && el.duration * 1000 > autoSlide ) { - autoSlide = ( el.duration * 1000 ) + 1000; + // length of that media. Not applicable if the slide + // is divided up into fragments. + if( currentSlide.querySelectorAll( '.fragment' ).length === 0 ) { + toArray( currentSlide.querySelectorAll( 'video, audio' ) ).forEach( function( el ) { + if( el.hasAttribute( 'data-autoplay' ) ) { + if( autoSlide && el.duration * 1000 > autoSlide ) { + autoSlide = ( el.duration * 1000 ) + 1000; + } } - } - } ); + } ); + } // Cue the next auto-slide if: // - There is an autoSlide value // - Auto-sliding isn't paused by the user // - The presentation isn't paused \ No newline at end of file