diff options
Diffstat (limited to 'js/reveal.js')
-rw-r--r-- | js/reveal.js | 623 |
1 files changed, 417 insertions, 206 deletions
diff --git a/js/reveal.js b/js/reveal.js index 033fe31..e7860ff 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -59,6 +59,10 @@ var Reveal = (function(){ // Turns fragments on and off globally fragments: true, + // Flags if the presentation is running in an embedded mode, + // i.e. contained within a limited portion of the screen + embedded: false, + // Number of milliseconds between automatically proceeding to the // next slide, disabled when set to 0, this value can be overwritten // by using a data-autoslide attribute on your slides @@ -68,7 +72,7 @@ var Reveal = (function(){ mouseWheel: false, // Apply a 3D roll to links on hover - rollingLinks: true, + rollingLinks: false, // Opens links in an iframe preview overlay previewLinks: false, @@ -83,18 +87,24 @@ var Reveal = (function(){ transitionSpeed: 'default', // default/fast/slow // Transition style for full page slide backgrounds - backgroundTransition: 'default', // default/linear + backgroundTransition: 'default', // default/linear/none + + // Number of slides away from the current that are visible + viewDistance: 3, // Script dependencies to load dependencies: [] }, + // Flags if reveal.js is loaded (has dispatched the 'ready' event) + loaded = false, + // The current auto-slide duration autoSlide = 0, // The horizontal and vertical index of the currently active slide - indexh = 0, - indexv = 0, + indexh, + indexv, // The previous and current slide HTML elements previousSlide, @@ -111,19 +121,14 @@ var Reveal = (function(){ // Cached references to DOM elements dom = {}, - // Detect support for CSS 3D transforms - supports3DTransforms = '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, + // Client support for CSS 3D transforms, see #checkCapabilities() + supports3DTransforms, - // Detect support for CSS 2D transforms - supports2DTransforms = '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, + // Client support for CSS 2D transforms, see #checkCapabilities() + supports2DTransforms, + + // Client is a mobile device, see #checkCapabilities() + isMobileDevice, // Throttles mouse wheel navigation lastMouseWheelStep = 0, @@ -149,8 +154,8 @@ var Reveal = (function(){ startY: 0, startSpan: 0, startCount: 0, - handled: false, - threshold: 80 + captured: false, + threshold: 40 }; /** @@ -158,6 +163,8 @@ var Reveal = (function(){ */ function initialize( options ) { + checkCapabilities(); + if( !supports2DTransforms && !supports3DTransforms ) { document.body.setAttribute( 'class', 'no-transforms' ); @@ -181,6 +188,136 @@ var Reveal = (function(){ } /** + * Inspect the client to see what it's capable of, this + * should only happens once per runtime. + */ + function checkCapabilities() { + + supports3DTransforms = '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; + + supports2DTransforms = '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; + + isMobileDevice = navigator.userAgent.match( /(iphone|ipod|android)/gi ); + + } + + /** + * Loads the dependencies of reveal.js. Dependencies are + * defined via the configuration option 'dependencies' + * and will be loaded prior to starting/binding reveal.js. + * Some dependencies may have an 'async' flag, if so they + * will load after reveal.js has been started up. + */ + function load() { + + var scripts = [], + scriptsAsync = []; + + for( var i = 0, len = config.dependencies.length; i < len; i++ ) { + var s = config.dependencies[i]; + + // Load if there's no condition or the condition is truthy + if( !s.condition || s.condition() ) { + if( s.async ) { + scriptsAsync.push( s.src ); + } + else { + scripts.push( s.src ); + } + + // Extension may contain callback functions + if( typeof s.callback === 'function' ) { + head.ready( s.src.match( /([\w\d_\-]*)\.?js$|[^\\\/]*$/i )[0], s.callback ); + } + } + } + + // Called once synchronous scripts finish loading + function proceed() { + if( scriptsAsync.length ) { + // Load asynchronous scripts + head.js.apply( null, scriptsAsync ); + } + + start(); + } + + if( scripts.length ) { + head.ready( proceed ); + + // Load synchronous scripts + head.js.apply( null, scripts ); + } + else { + proceed(); + } + + } + + /** + * Starts up reveal.js by binding input events and navigating + * to the current URL deeplink if there is one. + */ + function start() { + + // Make sure we've got all the DOM elements we need + setupDOM(); + + // Decorate the slide DOM elements with state classes (past/future) + setupSlides(); + + // Updates the presentation to match the current configuration values + configure(); + + // Read the initial hash + readURL(); + + // Notify listeners that the presentation is ready but use a 1ms + // timeout to ensure it's not fired synchronously after #initialize() + setTimeout( function() { + // Enable transitions now that we're loaded + dom.slides.classList.remove( 'no-transition' ); + + loaded = true; + + dispatchEvent( 'ready', { + 'indexh': indexh, + 'indexv': indexv, + 'currentSlide': currentSlide + } ); + }, 1 ); + + } + + /** + * Iterates through and decorates slides DOM elements with + * appropriate classes. + */ + function setupSlides() { + + var horizontalSlides = toArray( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ); + horizontalSlides.forEach( function( horizontalSlide ) { + + var verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) ); + verticalSlides.forEach( function( verticalSlide, y ) { + + if( y > 0 ) verticalSlide.classList.add( 'future' ); + + } ); + + } ); + + } + + /** * Finds and stores references to DOM elements which are * required by the presentation. If a required element is * not found, it is created. @@ -192,50 +329,30 @@ var Reveal = (function(){ dom.wrapper = document.querySelector( '.reveal' ); dom.slides = document.querySelector( '.reveal .slides' ); + // Prevent transitions while we're loading + dom.slides.classList.add( 'no-transition' ); + // Background element - if( !document.querySelector( '.reveal .backgrounds' ) ) { - dom.background = document.createElement( 'div' ); - dom.background.classList.add( 'backgrounds' ); - dom.wrapper.appendChild( dom.background ); - } + dom.background = createSingletonNode( dom.wrapper, 'div', 'backgrounds', null ); // Progress bar - if( !dom.wrapper.querySelector( '.progress' ) ) { - var progressElement = document.createElement( 'div' ); - progressElement.classList.add( 'progress' ); - progressElement.innerHTML = '<span></span>'; - dom.wrapper.appendChild( progressElement ); - } + dom.progress = createSingletonNode( dom.wrapper, 'div', 'progress', '<span></span>' ); + dom.progressbar = dom.progress.querySelector( 'span' ); // Arrow controls - if( !dom.wrapper.querySelector( '.controls' ) ) { - var controlsElement = document.createElement( 'aside' ); - controlsElement.classList.add( 'controls' ); - controlsElement.innerHTML = '<div class="navigate-left"></div>' + - '<div class="navigate-right"></div>' + - '<div class="navigate-up"></div>' + - '<div class="navigate-down"></div>'; - dom.wrapper.appendChild( controlsElement ); - } + createSingletonNode( dom.wrapper, 'aside', 'controls', + '<div class="navigate-left"></div>' + + '<div class="navigate-right"></div>' + + '<div class="navigate-up"></div>' + + '<div class="navigate-down"></div>' ); // State background element [DEPRECATED] - if( !dom.wrapper.querySelector( '.state-background' ) ) { - var stateBackgroundElement = document.createElement( 'div' ); - stateBackgroundElement.classList.add( 'state-background' ); - dom.wrapper.appendChild( stateBackgroundElement ); - } + createSingletonNode( dom.wrapper, 'div', 'state-background', null ); // Overlay graphic which is displayed during the paused mode - if( !dom.wrapper.querySelector( '.pause-overlay' ) ) { - var pausedElement = document.createElement( 'div' ); - pausedElement.classList.add( 'pause-overlay' ); - dom.wrapper.appendChild( pausedElement ); - } + createSingletonNode( dom.wrapper, 'div', 'pause-overlay', null ); // Cache references to elements - dom.progress = document.querySelector( '.reveal .progress' ); - dom.progressbar = document.querySelector( '.reveal .progress span' ); - if ( config.controls ) { dom.controls = document.querySelector( '.reveal .controls' ); @@ -251,6 +368,26 @@ var Reveal = (function(){ } /** + * Creates an HTML element and returns a reference to it. + * If the element already exists the existing instance will + * be returned. + */ + function createSingletonNode( container, tagname, classname, innerHTML ) { + + var node = container.querySelector( '.' + classname ); + if( !node ) { + node = document.createElement( tagname ); + node.classList.add( classname ); + if( innerHTML !== null ) { + node.innerHTML = innerHTML; + } + container.appendChild( node ); + } + return node; + + } + + /** * Creates the slide background elements and appends them * to the background container. One element is created per * slide no matter if the given slide has visible background. @@ -335,99 +472,6 @@ var Reveal = (function(){ } /** - * Hides the address bar if we're on a mobile device. - */ - function hideAddressBar() { - - if( /iphone|ipod|android/gi.test( navigator.userAgent ) && !/crios/gi.test( navigator.userAgent ) ) { - // Events that should trigger the address bar to hide - window.addEventListener( 'load', removeAddressBar, false ); - window.addEventListener( 'orientationchange', removeAddressBar, false ); - } - - } - - /** - * Loads the dependencies of reveal.js. Dependencies are - * defined via the configuration option 'dependencies' - * and will be loaded prior to starting/binding reveal.js. - * Some dependencies may have an 'async' flag, if so they - * will load after reveal.js has been started up. - */ - function load() { - - var scripts = [], - scriptsAsync = []; - - for( var i = 0, len = config.dependencies.length; i < len; i++ ) { - var s = config.dependencies[i]; - - // Load if there's no condition or the condition is truthy - if( !s.condition || s.condition() ) { - if( s.async ) { - scriptsAsync.push( s.src ); - } - else { - scripts.push( s.src ); - } - - // Extension may contain callback functions - if( typeof s.callback === 'function' ) { - head.ready( s.src.match( /([\w\d_\-]*)\.?js$|[^\\\/]*$/i )[0], s.callback ); - } - } - } - - // Called once synchronous scripts finish loading - function proceed() { - if( scriptsAsync.length ) { - // Load asynchronous scripts - head.js.apply( null, scriptsAsync ); - } - - start(); - } - - if( scripts.length ) { - head.ready( proceed ); - - // Load synchronous scripts - head.js.apply( null, scripts ); - } - else { - proceed(); - } - - } - - /** - * Starts up reveal.js by binding input events and navigating - * to the current URL deeplink if there is one. - */ - function start() { - - // Make sure we've got all the DOM elements we need - setupDOM(); - - // Updates the presentation to match the current configuration values - configure(); - - // Read the initial hash - readURL(); - - // Notify listeners that the presentation is ready but use a 1ms - // timeout to ensure it's not fired synchronously after #initialize() - setTimeout( function() { - dispatchEvent( 'ready', { - 'indexh': indexh, - 'indexv': indexv, - 'currentSlide': currentSlide - } ); - }, 1 ); - - } - - /** * Applies the configuration settings from the config * object. May be called multiple times. */ @@ -631,6 +675,19 @@ var Reveal = (function(){ } /** + * Applies a CSS transform to the target element. + */ + function transformElement( element, transform ) { + + element.style.WebkitTransform = transform; + element.style.MozTransform = transform; + element.style.msTransform = transform; + element.style.OTransform = transform; + element.style.transform = transform; + + } + + /** * Retrieves the height of the given element by looking * at the position and height of its immediate children. */ @@ -666,6 +723,48 @@ var Reveal = (function(){ } /** + * Returns the remaining height within the parent of the + * target element after subtracting the height of all + * siblings. + * + * remaining height = [parent height] - [ siblings height] + */ + function getRemainingHeight( element, height ) { + + height = height || 0; + + if( element ) { + var parent = element.parentNode; + var siblings = parent.childNodes; + + // Subtract the height of each sibling + toArray( siblings ).forEach( function( sibling ) { + + if( typeof sibling.offsetHeight === 'number' && sibling !== element ) { + + var styles = window.getComputedStyle( sibling ), + marginTop = parseInt( styles.marginTop, 10 ), + marginBottom = parseInt( styles.marginBottom, 10 ); + + height -= sibling.offsetHeight + marginTop + marginBottom; + + } + + } ); + + var elementStyles = window.getComputedStyle( element ); + + // Subtract the margins of the target element + height -= parseInt( elementStyles.marginTop, 10 ) + + parseInt( elementStyles.marginBottom, 10 ); + + } + + return height; + + } + + /** * Checks if this instance is being used to print a PDF. */ function isPrintingPDF() { @@ -675,6 +774,19 @@ var Reveal = (function(){ } /** + * Hides the address bar if we're on a mobile device. + */ + function hideAddressBar() { + + if( /iphone|ipod|android/gi.test( navigator.userAgent ) && !/crios/gi.test( navigator.userAgent ) ) { + // Events that should trigger the address bar to hide + window.addEventListener( 'load', removeAddressBar, false ); + window.addEventListener( 'orientationchange', removeAddressBar, false ); + } + + } + + /** * Causes the address bar to hide on mobile devices, * more vertical space ftw. */ @@ -886,7 +998,11 @@ var Reveal = (function(){ // Dimensions of the content var slideWidth = config.width, - slideHeight = config.height; + slideHeight = config.height, + slidePadding = 20; // TODO Dig this out of DOM + + // Layout the contents of the slides + layoutSlideContents( config.width, config.height, slidePadding ); // Slide width may be a percentage of available width if( typeof slideWidth === 'string' && /%$/.test( slideWidth ) ) { @@ -915,13 +1031,7 @@ var Reveal = (function(){ } // Apply scale transform as a fallback else { - var transform = 'translate(-50%, -50%) scale('+ scale +') translate(50%, 50%)'; - - dom.slides.style.WebkitTransform = transform; - dom.slides.style.MozTransform = transform; - dom.slides.style.msTransform = transform; - dom.slides.style.OTransform = transform; - dom.slides.style.transform = transform; + transformElement( dom.slides, 'translate(-50%, -50%) scale('+ scale +') translate(50%, 50%)' ); } // Select all slides, vertical and horizontal @@ -942,7 +1052,7 @@ var Reveal = (function(){ slide.style.top = 0; } else { - slide.style.top = Math.max( - ( getAbsoluteHeight( slide ) / 2 ) - 20, -slideHeight / 2 ) + 'px'; + slide.style.top = Math.max( - ( getAbsoluteHeight( slide ) / 2 ) - slidePadding, -slideHeight / 2 ) + 'px'; } } else { @@ -958,6 +1068,38 @@ var Reveal = (function(){ } /** + * Applies layout logic to the contents of all slides in + * the presentation. + */ + function layoutSlideContents( width, height, padding ) { + + // Handle sizing of elements with the 'stretch' class + toArray( dom.slides.querySelectorAll( 'section > .stretch' ) ).forEach( function( element ) { + + // Determine how much vertical space we can use + var remainingHeight = getRemainingHeight( element, ( height - ( padding * 2 ) ) ); + + // Consider the aspect ratio of media elements + if( /(img|video)/gi.test( element.nodeName ) ) { + var nw = element.naturalWidth || element.videoWidth, + nh = element.naturalHeight || element.videoHeight; + + var es = Math.min( width / nw, remainingHeight / nh ); + + element.style.width = ( nw * es ) + 'px'; + element.style.height = ( nh * es ) + 'px'; + + } + else { + element.style.width = width + 'px'; + element.style.height = remainingHeight + 'px'; + } + + } ); + + } + + /** * Stores the vertical index of a stack so that the same * vertical slide can be selected when navigating to and * from the stack. @@ -1010,6 +1152,9 @@ var Reveal = (function(){ var wasActive = dom.wrapper.classList.contains( 'overview' ); + // Vary the depth of the overview based on screen size + var depth = window.innerWidth < 400 ? 1000 : 2500; + dom.wrapper.classList.add( 'overview' ); dom.wrapper.classList.remove( 'exit-overview' ); @@ -1025,16 +1170,12 @@ var Reveal = (function(){ for( var i = 0, len1 = horizontalSlides.length; i < len1; i++ ) { var hslide = horizontalSlides[i], - hoffset = config.rtl ? -105 : 105, - htransform = 'translateZ(-2500px) translate(' + ( ( i - indexh ) * hoffset ) + '%, 0%)'; + hoffset = config.rtl ? -105 : 105; hslide.setAttribute( 'data-index-h', i ); - hslide.style.display = 'block'; - hslide.style.WebkitTransform = htransform; - hslide.style.MozTransform = htransform; - hslide.style.msTransform = htransform; - hslide.style.OTransform = htransform; - hslide.style.transform = htransform; + + // Apply CSS transform + transformElement( hslide, 'translateZ(-'+ depth +'px) translate(' + ( ( i - indexh ) * hoffset ) + '%, 0%)' ); if( hslide.classList.contains( 'stack' ) ) { @@ -1043,17 +1184,13 @@ var Reveal = (function(){ for( var j = 0, len2 = verticalSlides.length; j < len2; j++ ) { var verticalIndex = i === indexh ? indexv : getPreviousVerticalIndex( hslide ); - var vslide = verticalSlides[j], - vtransform = 'translate(0%, ' + ( ( j - verticalIndex ) * 105 ) + '%)'; + var vslide = verticalSlides[j]; vslide.setAttribute( 'data-index-h', i ); vslide.setAttribute( 'data-index-v', j ); - vslide.style.display = 'block'; - vslide.style.WebkitTransform = vtransform; - vslide.style.MozTransform = vtransform; - vslide.style.msTransform = vtransform; - vslide.style.OTransform = vtransform; - vslide.style.transform = vtransform; + + // Apply CSS transform + transformElement( vslide, 'translate(0%, ' + ( ( j - verticalIndex ) * 105 ) + '%)' ); // Navigate to this slide on click vslide.addEventListener( 'click', onOverviewSlideClicked, true ); @@ -1068,6 +1205,8 @@ var Reveal = (function(){ } } + updateSlidesVisibility(); + layout(); if( !wasActive ) { @@ -1117,11 +1256,7 @@ var Reveal = (function(){ element.style.display = ''; // Resets all transforms to use the external styles - element.style.WebkitTransform = ''; - element.style.MozTransform = ''; - element.style.msTransform = ''; - element.style.OTransform = ''; - element.style.transform = ''; + transformElement( element, '' ); element.removeEventListener( 'click', onOverviewSlideClicked, true ); } @@ -1302,13 +1437,16 @@ var Reveal = (function(){ // Reset the state array state.length = 0; - var indexhBefore = indexh, - indexvBefore = indexv; + var indexhBefore = indexh || 0, + indexvBefore = indexv || 0; // Activate and transition to the new slide indexh = updateSlides( HORIZONTAL_SLIDES_SELECTOR, h === undefined ? indexh : h ); indexv = updateSlides( VERTICAL_SLIDES_SELECTOR, v === undefined ? indexv : v ); + // Update the visibility of slides now that the indices have changed + updateSlidesVisibility(); + layout(); // Apply the new state @@ -1338,10 +1476,6 @@ var Reveal = (function(){ activateOverview(); } - // Update the URL hash after a delay since updating it mid-transition - // is likely to cause visual lag - writeURL( 1500 ); - // Find the current horizontal slide and any possible vertical slides // within it var currentHorizontalSlide = horizontalSlides[ indexh ], @@ -1413,6 +1547,9 @@ var Reveal = (function(){ updateProgress(); updateBackground(); + // Update the URL hash + writeURL(); + } /** @@ -1481,16 +1618,6 @@ var Reveal = (function(){ for( var i = 0; i < slidesLength; i++ ) { var element = slides[i]; - // Optimization; hide all slides that are three or more steps - // away from the present slide - if( isOverview() === false ) { - // The distance loops so that it measures 1 between the first - // and last slides - var distance = Math.abs( ( index - i ) % ( slidesLength - 3 ) ) || 0; - - element.style.display = distance > 3 ? 'none' : 'block'; - } - var reverse = config.rtl && !isVerticalSlide( element ); element.classList.remove( 'past' ); @@ -1507,6 +1634,13 @@ var Reveal = (function(){ else if( i > index ) { // Any element subsequent to index is given the 'future' class element.classList.add( reverse ? 'past' : 'future' ); + + var fragments = toArray( element.querySelectorAll( '.fragment.visible' ) ); + + // No fragments in future slides should be visible ahead of time + while( fragments.length ) { + fragments.pop().classList.remove( 'visible' ); + } } // If this element contains vertical slides @@ -1526,7 +1660,7 @@ var Reveal = (function(){ state = state.concat( slideState.split( ' ' ) ); } - // If this slide has a data-autoslide attribtue associated use this as + // If this slide has a data-autoslide attribute associated use this as // autoSlide value otherwise use the global configured time var slideAutoSlide = slides[index].getAttribute( 'data-autoslide' ); if( slideAutoSlide ) { @@ -1536,6 +1670,8 @@ var Reveal = (function(){ autoSlide = config.autoSlide; } + cueAutoSlide(); + } else { // Since there are no slides we can't be anywhere beyond the @@ -1548,6 +1684,61 @@ var Reveal = (function(){ } /** + * Optimization method; hide all slides that are far away + * from the present slide. + */ + function updateSlidesVisibility() { + + // Select all slides and convert the NodeList result to + // an array + var horizontalSlides = toArray( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ), + horizontalSlidesLength = horizontalSlides.length, + distanceX, + distanceY; + + if( horizontalSlidesLength ) { + + // The number of steps away from the present slide that will + // be visible + var viewDistance = isOverview() ? 10 : config.viewDistance; + + // Limit view distance on weaker devices + if( isMobileDevice ) { + viewDistance = isOverview() ? 6 : 1; + } + + for( var x = 0; x < horizontalSlidesLength; x++ ) { + var horizontalSlide = horizontalSlides[x]; + + var verticalSlides = toArray( horizontalSlide.querySelectorAll( 'section' ) ), + verticalSlidesLength = verticalSlides.length; + + // Loops so that it measures 1 between the first and last slides + distanceX = Math.abs( ( indexh - x ) % ( horizontalSlidesLength - viewDistance ) ) || 0; + + // Show the horizontal slide if it's within the view distance + horizontalSlide.style.display = distanceX > viewDistance ? 'none' : 'block'; + + if( verticalSlidesLength ) { + + var oy = getPreviousVerticalIndex( horizontalSlide ); + + for( var y = 0; y < verticalSlidesLength; y++ ) { + var verticalSlide = verticalSlides[y]; + + distanceY = x === indexh ? Math.abs( indexv - y ) : Math.abs( y - oy ); + + verticalSlide.style.display = ( distanceX + distanceY ) > viewDistance ? 'none' : 'block'; + } + + } + } + + } + + } + + /** * Updates the progress bar to reflect the current slide. */ function updateProgress() { @@ -1803,7 +1994,7 @@ var Reveal = (function(){ } // If the slide doesn't exist, navigate to the current slide else { - slide( indexh, indexv ); + slide( indexh || 0, indexv || 0 ); } } else { @@ -1811,7 +2002,9 @@ var Reveal = (function(){ var h = parseInt( bits[0], 10 ) || 0, v = parseInt( bits[1], 10 ) || 0; - slide( h, v ); + if( h !== indexh || v !== indexv ) { + slide( h, v ); + } } } @@ -1888,8 +2081,9 @@ var Reveal = (function(){ } if( !slide && currentSlide ) { - var visibleFragments = currentSlide.querySelectorAll( '.fragment.visible' ); - if( visibleFragments.length ) { + var hasFragments = currentSlide.querySelectorAll( '.fragment' ).length > 0; + if( hasFragments ) { + var visibleFragments = currentSlide.querySelectorAll( '.fragment.visible' ); f = visibleFragments.length; } } @@ -2119,7 +2313,7 @@ var Reveal = (function(){ var value = config.keyboard[ key ]; - // Calback function + // Callback function if( typeof value === 'function' ) { value.apply( null, [ event ] ); } @@ -2178,7 +2372,8 @@ var Reveal = (function(){ if( triggered ) { event.preventDefault(); } - else if ( event.keyCode === 27 && supports3DTransforms ) { + // ESC or O key + else if ( ( event.keyCode === 27 || event.keyCode === 79 ) && supports3DTransforms ) { toggleOverview(); event.preventDefault(); @@ -2220,11 +2415,11 @@ var Reveal = (function(){ function onTouchMove( event ) { // Each touch should only trigger one action - if( !touch.handled ) { + if( !touch.captured ) { var currentX = event.touches[0].clientX; var currentY = event.touches[0].clientY; - // If the touch started off with two points and still has + // If the touch started with two points and still has // two active touches; test for the pinch gesture if( event.touches.length === 2 && touch.startCount === 2 && config.overview ) { @@ -2240,7 +2435,7 @@ var Reveal = (function(){ // If the span is larger than the desire amount we've got // ourselves a pinch if( Math.abs( touch.startSpan - currentSpan ) > touch.threshold ) { - touch.handled = true; + touch.captured = true; if( currentSpan < touch.startSpan ) { activateOverview(); @@ -2260,23 +2455,34 @@ var Reveal = (function(){ deltaY = currentY - touch.startY; if( deltaX > touch.threshold && Math.abs( deltaX ) > Math.abs( deltaY ) ) { - touch.handled = true; + touch.captured = true; navigateLeft(); } else if( deltaX < -touch.threshold && Math.abs( deltaX ) > Math.abs( deltaY ) ) { - touch.handled = true; + touch.captured = true; navigateRight(); } else if( deltaY > touch.threshold ) { - touch.handled = true; + touch.captured = true; navigateUp(); } else if( deltaY < -touch.threshold ) { - touch.handled = true; + touch.captured = true; navigateDown(); } - event.preventDefault(); + // If we're embedded, only block touch events if they have + // triggered an action + if( config.embedded ) { + if( touch.captured || isVerticalSlide( currentSlide ) ) { + event.preventDefault(); + } + } + // Not embedded? Block them all to avoid needless tossing + // around of the viewport in iOS + else { + event.preventDefault(); + } } } @@ -2293,7 +2499,7 @@ var Reveal = (function(){ */ function onTouchEnd( event ) { - touch.handled = false; + touch.captured = false; } @@ -2561,6 +2767,11 @@ var Reveal = (function(){ } }, + // Checks if reveal.js has been loaded and is ready for use + isReady: function() { + return loaded; + }, + // Forward event binding to the reveal DOM element addEventListener: function( type, listener, useCapture ) { if( 'addEventListener' in window ) { |