diff options
Diffstat (limited to 'js/reveal.js')
-rw-r--r-- | js/reveal.js | 469 |
1 files changed, 309 insertions, 160 deletions
diff --git a/js/reveal.js b/js/reveal.js index 6ee0156..a4187e7 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -3,7 +3,7 @@ * http://lab.hakim.se/reveal-js * MIT licensed * - * Copyright (C) 2011-2013 Hakim El Hattab, http://hakim.se + * Copyright (C) 2013 Hakim El Hattab, http://hakim.se */ var Reveal = (function(){ @@ -44,7 +44,7 @@ var Reveal = (function(){ // Enable the slide overview mode overview: true, - // Vertical centering of slides + // Vertical centring of slides center: true, // Enables touch navigation on devices with touch input @@ -77,11 +77,10 @@ var Reveal = (function(){ dependencies: [] }, - // Stores if the next slide should be shown automatically - // after n milliseconds - autoSlide = config.autoSlide, + // The current auto-slide duration + autoSlide = 0, - // The horizontal and verical index of the currently active slide + // The horizontal and vertical index of the currently active slide indexh = 0, indexv = 0, @@ -129,6 +128,9 @@ var Reveal = (function(){ // A delay used to deactivate the overview mode deactivateOverviewTimeout = 0, + // Flags if the interaction event listeners are bound + eventsAreBound = false, + // Holds information about the currently ongoing touch input touch = { startX: 0, @@ -234,7 +236,7 @@ var Reveal = (function(){ */ function hideAddressBar() { - if( navigator.userAgent.match( /(iphone|ipod)/i ) ) { + 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 ); @@ -273,7 +275,7 @@ var Reveal = (function(){ } } - // Called once synchronous scritps finish loading + // Called once synchronous scripts finish loading function proceed() { if( scriptsAsync.length ) { // Load asynchronous scripts @@ -310,16 +312,9 @@ var Reveal = (function(){ // Updates the presentation to match the current configuration values configure(); - // Force an initial layout, will thereafter be invoked as the window - // is resized - layout(); - // Read the initial hash readURL(); - // Start auto-sliding if it's enabled - cueAutoSlide(); - // Notify listeners that the presentation is ready but use a 1ms // timeout to ensure it's not fired synchronously after #initialize() setTimeout( function() { @@ -335,40 +330,56 @@ var Reveal = (function(){ /** * Applies the configuration settings from the config object. */ - function configure() { + function configure( options ) { - if( supports3DTransforms === false ) { - config.transition = 'linear'; - } + dom.wrapper.classList.remove( config.transition ); - if( config.controls && dom.controls ) { - dom.controls.style.display = 'block'; - } + // New config options may be passed when this method + // is invoked through the API after initialization + if( typeof options === 'object' ) extend( config, options ); - if( config.progress && dom.progress ) { - dom.progress.style.display = 'block'; + // Force linear transition based on browser capabilities + if( supports3DTransforms === false ) config.transition = 'linear'; + + dom.wrapper.classList.add( config.transition ); + + if( dom.controls ) { + dom.controls.style.display = ( config.controls && dom.controls ) ? 'block' : 'none'; } - if( config.transition !== 'default' ) { - dom.wrapper.classList.add( config.transition ); + if( dom.progress ) { + dom.progress.style.display = ( config.progress && dom.progress ) ? 'block' : 'none'; } if( config.rtl ) { dom.wrapper.classList.add( 'rtl' ); } + else { + dom.wrapper.classList.remove( 'rtl' ); + } if( config.center ) { dom.wrapper.classList.add( 'center' ); } + else { + dom.wrapper.classList.remove( 'center' ); + } if( config.mouseWheel ) { document.addEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF document.addEventListener( 'mousewheel', onDocumentMouseScroll, false ); } + else { + document.removeEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF + document.removeEventListener( 'mousewheel', onDocumentMouseScroll, false ); + } // 3D links if( config.rollingLinks ) { - linkify(); + enable3DLinks(); + } + else { + disable3DLinks(); } // Load the theme in the config, if it's not already loaded @@ -383,6 +394,15 @@ var Reveal = (function(){ } } + // Force a layout to make sure the current config is accounted for + layout(); + + // Reflect the current autoSlide value + autoSlide = config.autoSlide; + + // Start auto-sliding if it's enabled + cueAutoSlide(); + } /** @@ -390,13 +410,15 @@ var Reveal = (function(){ */ function addEventListeners() { + eventsAreBound = true; + window.addEventListener( 'hashchange', onWindowHashChange, false ); window.addEventListener( 'resize', onWindowResize, false ); if( config.touch ) { - document.addEventListener( 'touchstart', onDocumentTouchStart, false ); - document.addEventListener( 'touchmove', onDocumentTouchMove, false ); - document.addEventListener( 'touchend', onDocumentTouchEnd, false ); + dom.wrapper.addEventListener( 'touchstart', onTouchStart, false ); + dom.wrapper.addEventListener( 'touchmove', onTouchMove, false ); + dom.wrapper.addEventListener( 'touchend', onTouchEnd, false ); } if( config.keyboard ) { @@ -404,17 +426,18 @@ var Reveal = (function(){ } if ( config.progress && dom.progress ) { - dom.progress.addEventListener( 'click', preventAndForward( onProgressClick ), false ); + dom.progress.addEventListener( 'click', onProgressClicked, false ); } if ( config.controls && dom.controls ) { - var actionEvent = 'ontouchstart' in window ? 'touchstart' : 'click'; - dom.controlsLeft.forEach( function( el ) { el.addEventListener( actionEvent, preventAndForward( navigateLeft ), false ); } ); - dom.controlsRight.forEach( function( el ) { el.addEventListener( actionEvent, preventAndForward( navigateRight ), false ); } ); - dom.controlsUp.forEach( function( el ) { el.addEventListener( actionEvent, preventAndForward( navigateUp ), false ); } ); - dom.controlsDown.forEach( function( el ) { el.addEventListener( actionEvent, preventAndForward( navigateDown ), false ); } ); - dom.controlsPrev.forEach( function( el ) { el.addEventListener( actionEvent, preventAndForward( navigatePrev ), false ); } ); - dom.controlsNext.forEach( function( el ) { el.addEventListener( actionEvent, preventAndForward( navigateNext ), false ); } ); + [ 'touchstart', 'click' ].forEach( function( eventName ) { + dom.controlsLeft.forEach( function( el ) { el.addEventListener( eventName, onNavigateLeftClicked, false ); } ); + dom.controlsRight.forEach( function( el ) { el.addEventListener( eventName, onNavigateRightClicked, false ); } ); + dom.controlsUp.forEach( function( el ) { el.addEventListener( eventName, onNavigateUpClicked, false ); } ); + dom.controlsDown.forEach( function( el ) { el.addEventListener( eventName, onNavigateDownClicked, false ); } ); + dom.controlsPrev.forEach( function( el ) { el.addEventListener( eventName, onNavigatePrevClicked, false ); } ); + dom.controlsNext.forEach( function( el ) { el.addEventListener( eventName, onNavigateNextClicked, false ); } ); + } ); } } @@ -424,28 +447,31 @@ var Reveal = (function(){ */ function removeEventListeners() { + eventsAreBound = false; + document.removeEventListener( 'keydown', onDocumentKeyDown, false ); window.removeEventListener( 'hashchange', onWindowHashChange, false ); window.removeEventListener( 'resize', onWindowResize, false ); if( config.touch ) { - document.removeEventListener( 'touchstart', onDocumentTouchStart, false ); - document.removeEventListener( 'touchmove', onDocumentTouchMove, false ); - document.removeEventListener( 'touchend', onDocumentTouchEnd, false ); + dom.wrapper.removeEventListener( 'touchstart', onTouchStart, false ); + dom.wrapper.removeEventListener( 'touchmove', onTouchMove, false ); + dom.wrapper.removeEventListener( 'touchend', onTouchEnd, false ); } if ( config.progress && dom.progress ) { - dom.progress.removeEventListener( 'click', preventAndForward( onProgressClick ), false ); + dom.progress.removeEventListener( 'click', onProgressClicked, false ); } if ( config.controls && dom.controls ) { - var actionEvent = 'ontouchstart' in window ? 'touchstart' : 'click'; - dom.controlsLeft.forEach( function( el ) { el.removeEventListener( actionEvent, preventAndForward( navigateLeft ), false ); } ); - dom.controlsRight.forEach( function( el ) { el.removeEventListener( actionEvent, preventAndForward( navigateRight ), false ); } ); - dom.controlsUp.forEach( function( el ) { el.removeEventListener( actionEvent, preventAndForward( navigateUp ), false ); } ); - dom.controlsDown.forEach( function( el ) { el.removeEventListener( actionEvent, preventAndForward( navigateDown ), false ); } ); - dom.controlsPrev.forEach( function( el ) { el.removeEventListener( actionEvent, preventAndForward( navigatePrev ), false ); } ); - dom.controlsNext.forEach( function( el ) { el.removeEventListener( actionEvent, preventAndForward( navigateNext ), false ); } ); + [ 'touchstart', 'click' ].forEach( function( eventName ) { + dom.controlsLeft.forEach( function( el ) { el.removeEventListener( eventName, onNavigateLeftClicked, false ); } ); + dom.controlsRight.forEach( function( el ) { el.removeEventListener( eventName, onNavigateRightClicked, false ); } ); + dom.controlsUp.forEach( function( el ) { el.removeEventListener( eventName, onNavigateUpClicked, false ); } ); + dom.controlsDown.forEach( function( el ) { el.removeEventListener( eventName, onNavigateDownClicked, false ); } ); + dom.controlsPrev.forEach( function( el ) { el.removeEventListener( eventName, onNavigatePrevClicked, false ); } ); + dom.controlsNext.forEach( function( el ) { el.removeEventListener( eventName, onNavigateNextClicked, false ); } ); + } ); } } @@ -488,22 +514,6 @@ var Reveal = (function(){ } /** - * Prevents an events defaults behavior calls the - * specified delegate. - * - * @param {Function} delegate The method to call - * after the wrapper has been executed - */ - function preventAndForward( delegate ) { - - return function( event ) { - event.preventDefault(); - delegate.call( null, event ); - }; - - } - - /** * Causes the address bar to hide on mobile devices, * more vertical space ftw. */ @@ -540,22 +550,22 @@ var Reveal = (function(){ /** * Wrap all links in 3D goodness. */ - function linkify() { + function enable3DLinks() { if( supports3DTransforms && !( 'msPerspective' in document.body.style ) ) { - var nodes = document.querySelectorAll( SLIDES_SELECTOR + ' a:not(.image)' ); + var anchors = document.querySelectorAll( SLIDES_SELECTOR + ' a:not(.image)' ); - for( var i = 0, len = nodes.length; i < len; i++ ) { - var node = nodes[i]; + for( var i = 0, len = anchors.length; i < len; i++ ) { + var anchor = anchors[i]; - if( node.textContent && !node.querySelector( '*' ) && ( !node.className || !node.classList.contains( node, 'roll' ) ) ) { + if( anchor.textContent && !anchor.querySelector( '*' ) && ( !anchor.className || !anchor.classList.contains( anchor, 'roll' ) ) ) { var span = document.createElement('span'); - span.setAttribute('data-title', node.text); - span.innerHTML = node.innerHTML; + span.setAttribute('data-title', anchor.text); + span.innerHTML = anchor.innerHTML; - node.classList.add( 'roll' ); - node.innerHTML = ''; - node.appendChild(span); + anchor.classList.add( 'roll' ); + anchor.innerHTML = ''; + anchor.appendChild(span); } } } @@ -563,67 +573,115 @@ var Reveal = (function(){ } /** + * Unwrap all 3D links. + */ + function disable3DLinks() { + + var anchors = document.querySelectorAll( SLIDES_SELECTOR + ' a.roll' ); + + for( var i = 0, len = anchors.length; i < len; i++ ) { + var anchor = anchors[i]; + var span = anchor.querySelector( 'span' ); + + if( span ) { + anchor.classList.remove( 'roll' ); + anchor.innerHTML = span.innerHTML; + } + } + + } + + /** + * Return a sorted fragments list, ordered by an increasing + * "data-fragment-index" attribute. + * + * Fragments will be revealed in the order that they are returned by + * this function, so you can use the index attributes to control the + * order of fragment appearance. + * + * To maintain a sensible default fragment order, fragments are presumed + * to be passed in document order. This function adds a "fragment-index" + * attribute to each node if such an attribute is not already present, + * and sets that attribute to an integer value which is the position of + * the fragment within the fragments list. + */ + function sortFragments( fragments ) { + + var a = toArray( fragments ); + + a.forEach( function( el, idx ) { + if( !el.hasAttribute( 'data-fragment-index' ) ) { + el.setAttribute( 'data-fragment-index', idx ); + } + } ); + + a.sort( function( l, r ) { + return l.getAttribute( 'data-fragment-index' ) - r.getAttribute( 'data-fragment-index'); + } ); + + return a + + } + + /** * Applies JavaScript-controlled layout rules to the * presentation. */ function layout() { - // Available space to scale within - var availableWidth = dom.wrapper.offsetWidth, - availableHeight = dom.wrapper.offsetHeight; + if( dom.wrapper ) { - // Reduce availabe space by margin - availableWidth -= ( availableHeight * config.margin ); - availableHeight -= ( availableHeight * config.margin ); + // Available space to scale within + var availableWidth = dom.wrapper.offsetWidth, + availableHeight = dom.wrapper.offsetHeight; - // Dimensions of the content - var slideWidth = config.width, - slideHeight = config.height; + // Reduce available space by margin + availableWidth -= ( availableHeight * config.margin ); + availableHeight -= ( availableHeight * config.margin ); - // Slide width may be a percentage of available width - if( typeof slideWidth === 'string' && /%$/.test( slideWidth ) ) { - slideWidth = parseInt( slideWidth, 10 ) / 100 * availableWidth; - } + // Dimensions of the content + var slideWidth = config.width, + slideHeight = config.height; - // Slide height may be a percentage of available height - if( typeof slideHeight === 'string' && /%$/.test( slideHeight ) ) { - slideHeight = parseInt( slideHeight, 10 ) / 100 * availableHeight; - } + // Slide width may be a percentage of available width + if( typeof slideWidth === 'string' && /%$/.test( slideWidth ) ) { + slideWidth = parseInt( slideWidth, 10 ) / 100 * availableWidth; + } - dom.slides.style.width = slideWidth + 'px'; - dom.slides.style.height = slideHeight + 'px'; + // Slide height may be a percentage of available height + if( typeof slideHeight === 'string' && /%$/.test( slideHeight ) ) { + slideHeight = parseInt( slideHeight, 10 ) / 100 * availableHeight; + } - // Determine scale of content to fit within available space - scale = Math.min( availableWidth / slideWidth, availableHeight / slideHeight ); + dom.slides.style.width = slideWidth + 'px'; + dom.slides.style.height = slideHeight + 'px'; - // Respect max/min scale settings - scale = Math.max( scale, config.minScale ); - scale = Math.min( scale, config.maxScale ); + // Determine scale of content to fit within available space + scale = Math.min( availableWidth / slideWidth, availableHeight / slideHeight ); - // Prefer applying scale via zoom since Chrome blurs scaled content - // with nested transforms - if( typeof dom.slides.style.zoom !== 'undefined' && !navigator.userAgent.match( /(iphone|ipod|android)/gi ) ) { - dom.slides.style.zoom = scale; - } - // Apply scale transform as a fallback - else { - var transform = 'translate(-50%, -50%) scale('+ scale +') translate(50%, 50%)'; + // Respect max/min scale settings + scale = Math.max( scale, config.minScale ); + scale = Math.min( scale, config.maxScale ); - 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; - } + // Prefer applying scale via zoom since Chrome blurs scaled content + // with nested transforms + if( typeof dom.slides.style.zoom !== 'undefined' && !navigator.userAgent.match( /(iphone|ipod|ipad|android)/gi ) ) { + dom.slides.style.zoom = scale; + } + // Apply scale transform as a fallback + else { + var transform = 'translate(-50%, -50%) scale('+ scale +') translate(50%, 50%)'; - if( config.center ) { + 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; + } // Select all slides, vertical and horizontal var slides = toArray( document.querySelectorAll( SLIDES_SELECTOR ) ); - // Determine the minimum top offset for slides - var minTop = -slideHeight / 2; - for( var i = 0, len = slides.length; i < len; i++ ) { var slide = slides[ i ]; @@ -632,14 +690,20 @@ var Reveal = (function(){ continue; } - // Vertical stacks are not centered since their section - // children will be - if( slide.classList.contains( 'stack' ) ) { - slide.style.top = 0; + if( config.center ) { + // Vertical stacks are not centred since their section + // children will be + if( slide.classList.contains( 'stack' ) ) { + slide.style.top = 0; + } + else { + slide.style.top = Math.max( - ( slide.offsetHeight / 2 ) - 20, -slideHeight / 2 ) + 'px'; + } } else { - slide.style.top = Math.max( - ( slide.offsetHeight / 2 ) - 20, minTop ) + 'px'; + slide.style.top = ''; } + } } @@ -656,14 +720,14 @@ var Reveal = (function(){ */ function setPreviousVerticalIndex( stack, v ) { - if( stack ) { + if( typeof stack === 'object' && typeof stack.setAttribute === 'function' ) { stack.setAttribute( 'data-previous-indexv', v || 0 ); } } /** - * Retrieves the vertical index which was stored using + * Retrieves the vertical index which was stored using * #setPreviousVerticalIndex() or 0 if no previous index * exists. * @@ -671,7 +735,7 @@ var Reveal = (function(){ */ function getPreviousVerticalIndex( stack ) { - if( stack && stack.classList.contains( 'stack' ) ) { + if( typeof stack === 'object' && typeof stack.setAttribute === 'function' && stack.classList.contains( 'stack' ) ) { return parseInt( stack.getAttribute( 'data-previous-indexv' ) || 0, 10 ); } @@ -691,6 +755,9 @@ var Reveal = (function(){ // Only proceed if enabled in config if( config.overview ) { + // Don't auto-slide while in overview mode + cancelAutoSlide(); + var wasActive = dom.wrapper.classList.contains( 'overview' ); dom.wrapper.classList.add( 'overview' ); @@ -810,6 +877,8 @@ var Reveal = (function(){ slide( indexh, indexv ); + cueAutoSlide(); + // Notify observers of the overview hiding dispatchEvent( 'overviewhidden', { 'indexh': indexh, @@ -833,7 +902,7 @@ var Reveal = (function(){ override ? activateOverview() : deactivateOverview(); } else { - isOverviewActive() ? deactivateOverview() : activateOverview(); + isOverview() ? deactivateOverview() : activateOverview(); } } @@ -844,7 +913,7 @@ var Reveal = (function(){ * @return {Boolean} true if the overview is active, * false otherwise */ - function isOverviewActive() { + function isOverview() { return dom.wrapper.classList.contains( 'overview' ); @@ -878,8 +947,15 @@ var Reveal = (function(){ */ function pause() { + var wasPaused = dom.wrapper.classList.contains( 'paused' ); + + cancelAutoSlide(); dom.wrapper.classList.add( 'paused' ); + if( wasPaused === false ) { + dispatchEvent( 'paused' ); + } + } /** @@ -887,8 +963,15 @@ var Reveal = (function(){ */ function resume() { + var wasPaused = dom.wrapper.classList.contains( 'paused' ); + + cueAutoSlide(); dom.wrapper.classList.remove( 'paused' ); + if( wasPaused ) { + dispatchEvent( 'resumed' ); + } + } /** @@ -982,7 +1065,7 @@ var Reveal = (function(){ } // If the overview is active, re-activate it to update positions - if( isOverviewActive() ) { + if( isOverview() ) { activateOverview(); } @@ -1001,7 +1084,7 @@ var Reveal = (function(){ // Show fragment, if specified if( typeof f !== 'undefined' ) { - var fragments = currentSlide.querySelectorAll( '.fragment' ); + var fragments = sortFragments( currentSlide.querySelectorAll( '.fragment' ) ); toArray( fragments ).forEach( function( fragment, indexf ) { if( indexf < f ) { @@ -1093,7 +1176,7 @@ var Reveal = (function(){ // Optimization; hide all slides that are three or more steps // away from the present slide - if( isOverviewActive() === false ) { + 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; @@ -1243,8 +1326,8 @@ var Reveal = (function(){ verticalSlides = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR ); return { - left: indexh > 0, - right: indexh < horizontalSlides.length - 1, + left: indexh > 0 || config.loop, + right: indexh < horizontalSlides.length - 1 || config.loop, up: indexv > 0, down: indexv < verticalSlides.length - 1 }; @@ -1372,7 +1455,8 @@ var Reveal = (function(){ // Vertical slides: if( document.querySelector( VERTICAL_SLIDES_SELECTOR + '.present' ) ) { - var verticalFragments = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR + '.present .fragment:not(.visible)' ); + var verticalFragments = sortFragments( document.querySelectorAll( VERTICAL_SLIDES_SELECTOR + '.present .fragment:not(.visible)' ) ); + if( verticalFragments.length ) { verticalFragments[0].classList.add( 'visible' ); @@ -1383,7 +1467,8 @@ var Reveal = (function(){ } // Horizontal slides: else { - var horizontalFragments = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.present .fragment:not(.visible)' ); + var horizontalFragments = sortFragments( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.present .fragment:not(.visible)' ) ); + if( horizontalFragments.length ) { horizontalFragments[0].classList.add( 'visible' ); @@ -1407,7 +1492,8 @@ var Reveal = (function(){ // Vertical slides: if( document.querySelector( VERTICAL_SLIDES_SELECTOR + '.present' ) ) { - var verticalFragments = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR + '.present .fragment.visible' ); + var verticalFragments = sortFragments( document.querySelectorAll( VERTICAL_SLIDES_SELECTOR + '.present .fragment.visible' ) ); + if( verticalFragments.length ) { verticalFragments[ verticalFragments.length - 1 ].classList.remove( 'visible' ); @@ -1418,7 +1504,8 @@ var Reveal = (function(){ } // Horizontal slides: else { - var horizontalFragments = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.present .fragment.visible' ); + var horizontalFragments = sortFragments( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.present .fragment.visible' ) ); + if( horizontalFragments.length ) { horizontalFragments[ horizontalFragments.length - 1 ].classList.remove( 'visible' ); @@ -1440,16 +1527,25 @@ var Reveal = (function(){ clearTimeout( autoSlideTimeout ); // Cue the next auto-slide if enabled - if( autoSlide ) { + if( autoSlide && !isPaused() && !isOverview() ) { autoSlideTimeout = setTimeout( navigateNext, autoSlide ); } } + /** + * Cancels any ongoing request to auto-slide. + */ + function cancelAutoSlide() { + + clearTimeout( autoSlideTimeout ); + + } + function navigateLeft() { // Prioritize hiding fragments - if( availableRoutes().left && isOverviewActive() || previousFragment() === false ) { + if( availableRoutes().left && ( isOverview() || previousFragment() === false ) ) { slide( indexh - 1 ); } @@ -1458,7 +1554,7 @@ var Reveal = (function(){ function navigateRight() { // Prioritize revealing fragments - if( availableRoutes().right && isOverviewActive() || nextFragment() === false ) { + if( availableRoutes().right && ( isOverview() || nextFragment() === false ) ) { slide( indexh + 1 ); } @@ -1467,7 +1563,7 @@ var Reveal = (function(){ function navigateUp() { // Prioritize hiding fragments - if( availableRoutes().up && isOverviewActive() || previousFragment() === false ) { + if( availableRoutes().up && isOverview() || previousFragment() === false ) { slide( indexh, indexv - 1 ); } @@ -1476,7 +1572,7 @@ var Reveal = (function(){ function navigateDown() { // Prioritize revealing fragments - if( availableRoutes().down && isOverviewActive() || nextFragment() === false ) { + if( availableRoutes().down && isOverview() || nextFragment() === false ) { slide( indexh, indexv + 1 ); } @@ -1545,10 +1641,15 @@ var Reveal = (function(){ // Disregard the event if there's a focused element or a // keyboard modifier key is present - if ( hasFocus || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return; + if( hasFocus || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return; var triggered = true; + // while paused only allow "unpausing" keyboard events (b and .) + if( isPaused() && [66,190,191].indexOf( event.keyCode ) === -1 ) { + return false; + } + switch( event.keyCode ) { // p, page up case 80: case 33: navigatePrev(); break; @@ -1567,9 +1668,9 @@ var Reveal = (function(){ // end case 35: slide( Number.MAX_VALUE ); break; // space - case 32: isOverviewActive() ? deactivateOverview() : navigateNext(); break; + case 32: isOverview() ? deactivateOverview() : navigateNext(); break; // return - case 13: isOverviewActive() ? deactivateOverview() : triggered = false; break; + case 13: isOverview() ? deactivateOverview() : triggered = false; break; // b, period, Logitech presenter tools "black screen" button case 66: case 190: case 191: togglePause(); break; // f @@ -1596,10 +1697,10 @@ var Reveal = (function(){ } /** - * Handler for the document level 'touchstart' event, - * enables support for swipe and pinch gestures. + * Handler for the 'touchstart' event, enables support for + * swipe and pinch gestures. */ - function onDocumentTouchStart( event ) { + function onTouchStart( event ) { touch.startX = event.touches[0].clientX; touch.startY = event.touches[0].clientY; @@ -1620,9 +1721,9 @@ var Reveal = (function(){ } /** - * Handler for the document level 'touchmove' event. + * Handler for the 'touchmove' event. */ - function onDocumentTouchMove( event ) { + function onTouchMove( event ) { // Each touch should only trigger one action if( !touch.handled ) { @@ -1694,9 +1795,9 @@ var Reveal = (function(){ } /** - * Handler for the document level 'touchend' event. + * Handler for the 'touchend' event. */ - function onDocumentTouchEnd( event ) { + function onTouchEnd( event ) { touch.handled = false; @@ -1728,7 +1829,9 @@ var Reveal = (function(){ * * ( clickX / presentationWidth ) * numberOfSlides */ - function onProgressClick( event ) { + function onProgressClicked( event ) { + + event.preventDefault(); var slidesTotal = toArray( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) ).length; var slideIndex = Math.floor( ( event.clientX / dom.wrapper.offsetWidth ) * slidesTotal ); @@ -1738,6 +1841,16 @@ var Reveal = (function(){ } /** + * Event handler for navigation control buttons. + */ + function onNavigateLeftClicked( event ) { event.preventDefault(); navigateLeft(); } + function onNavigateRightClicked( event ) { event.preventDefault(); navigateRight(); } + function onNavigateUpClicked( event ) { event.preventDefault(); navigateUp(); } + function onNavigateDownClicked( event ) { event.preventDefault(); navigateDown(); } + function onNavigatePrevClicked( event ) { event.preventDefault(); navigatePrev(); } + function onNavigateNextClicked( event ) { event.preventDefault(); navigateNext(); } + + /** * Handler for the window level 'hashchange' event. */ function onWindowHashChange( event ) { @@ -1762,22 +1875,26 @@ var Reveal = (function(){ // TODO There's a bug here where the event listeners are not // removed after deactivating the overview. - if( isOverviewActive() ) { + if( eventsAreBound && isOverview() ) { event.preventDefault(); - deactivateOverview(); - var element = event.target; while( element && !element.nodeName.match( /section/gi ) ) { element = element.parentNode; } - if( element.nodeName.match( /section/gi ) ) { - var h = parseInt( element.getAttribute( 'data-index-h' ), 10 ), - v = parseInt( element.getAttribute( 'data-index-v' ), 10 ); + if( element && !element.classList.contains( 'disabled' ) ) { + + deactivateOverview(); + + if( element.nodeName.match( /section/gi ) ) { + var h = parseInt( element.getAttribute( 'data-index-h' ), 10 ), + v = parseInt( element.getAttribute( 'data-index-v' ), 10 ); + + slide( h, v ); + } - slide( h, v ); } } @@ -1791,6 +1908,7 @@ var Reveal = (function(){ return { initialize: initialize, + configure: configure, // Navigation methods slide: slide, @@ -1821,6 +1939,10 @@ var Reveal = (function(){ // Toggles the "black screen" mode on/off togglePause: togglePause, + // State checks + isOverview: isOverview, + isPaused: isPaused, + // Adds or removes all internal event listeners (such as keyboard) addEventListeners: addEventListeners, removeEventListeners: removeEventListeners, @@ -1828,6 +1950,18 @@ var Reveal = (function(){ // Returns the indices of the current, or specified, slide getIndices: getIndices, + // Returns the slide at the specified index, y is optional + getSlide: function( x, y ) { + var horizontalSlide = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR )[ x ]; + var verticalSlides = horizontalSlide && horizontalSlide.querySelectorAll( 'section' ); + + if( typeof y !== 'undefined' ) { + return verticalSlides ? verticalSlides[ y ] : undefined; + } + + return horizontalSlide; + }, + // Returns the previous slide element, may be null getPreviousSlide: function() { return previousSlide; @@ -1854,6 +1988,21 @@ var Reveal = (function(){ return query; }, + // Returns true if we're currently on the first slide + isFirstSlide: function() { + return document.querySelector( SLIDES_SELECTOR + '.past' ) == null ? true : false; + }, + + // Returns true if we're currently on the last slide + isLastSlide: function() { + if( currentSlide && currentSlide.classList.contains( '.stack' ) ) { + return currentSlide.querySelector( SLIDES_SELECTOR + '.future' ) == null ? true : false; + } + else { + return document.querySelector( SLIDES_SELECTOR + '.future' ) == null ? true : false; + } + }, + // Forward event binding to the reveal DOM element addEventListener: function( type, listener, useCapture ) { if( 'addEventListener' in window ) { @@ -1867,4 +2016,4 @@ var Reveal = (function(){ } }; -})();
\ No newline at end of file +})(); |