summaryrefslogtreecommitdiffhomepage
path: root/js/reveal.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/reveal.js')
-rw-r--r--js/reveal.js469
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
+})();