Newer
Older
* http://lab.hakim.se/reveal-js
* MIT licensed
* Copyright (C) 2013 Hakim El Hattab, http://hakim.se
var Reveal = (function(){
'use strict';
var SLIDES_SELECTOR = '.reveal .slides section',
HORIZONTAL_SLIDES_SELECTOR = '.reveal .slides>section',
VERTICAL_SLIDES_SELECTOR = '.reveal .slides>section.present>section',
HOME_SLIDE_SELECTOR = '.reveal .slides>section:first-child',
// Configurations defaults, can be overridden at initialization time

Hakim El Hattab
committed

hakimel
committed
// The "normal" size of the presentation, aspect ratio will be preserved
// when the presentation is scaled to fit different resolutions

hakimel
committed
// Factor of the display size that should remain empty around the content

hakimel
committed
margin: 0.1,

Hakim El Hattab
committed
// Bounds for smallest/largest possible scale to apply to content
minScale: 0.2,

Hakim El Hattab
committed
// Display controls in the bottom right corner

Hakim El Hattab
committed
// Display a presentation progress bar
progress: true,
// Push each slide change to the browser history

Hakim El Hattab
committed
// Enable keyboard shortcuts for navigation
keyboard: true,
// Enable the slide overview mode
overview: true,

Hakim El Hattab
committed
center: true,
// Enables touch navigation on devices with touch input
touch: true,

Hakim El Hattab
committed
// Loop the presentation

Hakim El Hattab
committed
// Change the presentation direction to be RTL
// 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

Hakim El Hattab
committed
autoSlide: 0,
// Enable slide navigation via mouse wheel

Hakim El Hattab
committed
mouseWheel: false,

Hakim El Hattab
committed
// Apply a 3D roll to links on hover

Hakim El Hattab
committed

Hakim El Hattab
committed
// Transition style
transition: 'default', // default/cube/page/concave/zoom/linear/fade/none
// Transition speed
transitionSpeed: 'default', // default/fast/slow
// Script dependencies to load
dependencies: []
// The current auto-slide duration
autoSlide = 0,
// The horizontal and vertical index of the currently active slide

Hakim El Hattab
committed
indexh = 0,
indexv = 0,
// The previous and current slide HTML elements
previousSlide,
currentSlide,
// Slides may hold a data-state attribute which we pick up and apply
// as a class to the body. This list contains the combined state of

Hakim El Hattab
committed
// all current slides.
state = [],

Hakim El Hattab
committed
// The current scale of the presentation (see width/height config)
scale = 1,
dom = {},
// Detect support for CSS 3D transforms

hakimel
committed
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,
// 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,

Hakim El Hattab
committed
mouseWheelTimeout = 0,

Hakim El Hattab
committed
// An interval used to automatically move on to the next slide
autoSlideTimeout = 0,

Hakim El Hattab
committed
// Delays updates to the URL due to a Chrome thumbnailer bug
activateOverviewTimeout = 0,
// Flags if the interaction event listeners are bound
eventsAreBound = false,
// Holds information about the currently ongoing touch input
touch = {
startX: 0,
startY: 0,
startSpan: 0,
startCount: 0,
handled: false,
threshold: 80
* Starts up the presentation if the client is capable.
function initialize( options ) {
if( !supports2DTransforms && !supports3DTransforms ) {
document.body.setAttribute( 'class', 'no-transforms' );
// If the browser doesn't support core features we won't be
// using JavaScript to control the presentation
// Force a layout when the whole page, incl fonts, has loaded
window.addEventListener( 'load', layout, false );
// Copy options over to our config object
extend( config, options );

Hakim El Hattab
committed
// Hide the address bar in mobile browsers
hideAddressBar();
// Loads the dependencies and continues to #start() once done
load();

Hakim El Hattab
committed
}
/**
* Finds and stores references to DOM elements which are
* required by the presentation. If a required element is

Hakim El Hattab
committed
* not found, it is created.
*/
function setupDOM() {

Hakim El Hattab
committed
// Cache references to key DOM elements
dom.theme = document.querySelector( '#theme' );
dom.wrapper = document.querySelector( '.reveal' );
dom.slides = document.querySelector( '.reveal .slides' );

Hakim El Hattab
committed
// Progress bar
if( !dom.wrapper.querySelector( '.progress' ) ) {

Hakim El Hattab
committed
var progressElement = document.createElement( 'div' );
progressElement.classList.add( 'progress' );
progressElement.innerHTML = '<span></span>';
dom.wrapper.appendChild( progressElement );
}
// Arrow controls
if( !dom.wrapper.querySelector( '.controls' ) ) {

Hakim El Hattab
committed
var controlsElement = document.createElement( 'aside' );
controlsElement.classList.add( 'controls' );

Hakim El Hattab
committed
controlsElement.innerHTML = '<div class="navigate-left"></div>' +
'<div class="navigate-right"></div>' +
'<div class="navigate-up"></div>' +

Hakim El Hattab
committed
'<div class="navigate-down"></div>';

Hakim El Hattab
committed
dom.wrapper.appendChild( controlsElement );
}
// Presentation background element
if( !dom.wrapper.querySelector( '.state-background' ) ) {
var backgroundElement = document.createElement( 'div' );
backgroundElement.classList.add( 'state-background' );
dom.wrapper.appendChild( backgroundElement );
}
// 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 );
}
// Cache references to elements
dom.progress = document.querySelector( '.reveal .progress' );
dom.progressbar = document.querySelector( '.reveal .progress span' );
dom.controls = document.querySelector( '.reveal .controls' );

Hakim El Hattab
committed
// There can be multiple instances of controls throughout the page
dom.controlsLeft = toArray( document.querySelectorAll( '.navigate-left' ) );
dom.controlsRight = toArray( document.querySelectorAll( '.navigate-right' ) );
dom.controlsUp = toArray( document.querySelectorAll( '.navigate-up' ) );
dom.controlsDown = toArray( document.querySelectorAll( '.navigate-down' ) );
dom.controlsPrev = toArray( document.querySelectorAll( '.navigate-prev' ) );
dom.controlsNext = toArray( document.querySelectorAll( '.navigate-next' ) );

Hakim El Hattab
committed
}

Hakim El Hattab
committed
/**
* 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() {

Hakim El Hattab
committed
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.
*/
function configure( options ) {
dom.wrapper.classList.remove( config.transition );
// New config options may be passed when this method
// is invoked through the API after initialization
if( typeof options === 'object' ) extend( config, options );
// Force linear transition based on browser capabilities
if( supports3DTransforms === false ) config.transition = 'linear';
dom.wrapper.classList.add( config.transition );
dom.wrapper.setAttribute( 'data-transition-speed', config.transitionSpeed );

Ben Houston
committed
dom.controls.style.display = ( config.controls && dom.controls ) ? 'block' : 'none';

Ben Houston
committed

Ben Houston
committed
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' );
}
document.addEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF
document.addEventListener( 'mousewheel', onDocumentMouseScroll, false );
else {
document.removeEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF
document.removeEventListener( 'mousewheel', onDocumentMouseScroll, false );
}

Hakim El Hattab
committed
// 3D links
if( config.rollingLinks ) {
enable3DLinks();
}
else {
disable3DLinks();

Hakim El Hattab
committed
// Load the theme in the config, if it's not already loaded
if( config.theme && dom.theme ) {
var themeURL = dom.theme.getAttribute( 'href' );
var themeFinder = /[^\/]*?(?=\.css)/;
var themeName = themeURL.match(themeFinder)[0];
if( config.theme !== themeName ) {
themeURL = themeURL.replace(themeFinder, config.theme);
dom.theme.setAttribute( 'href', themeURL );
}
}

Hakim El Hattab
committed
postConfigure();
}
/**
* Updates various parts of the presentatio after the
* configuration has changed.
*/
function postConfigure() {
// Subscribe to input
removeEventListeners();
addEventListeners();
// 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();

Hakim El Hattab
committed
/**
* Binds all event listeners.
*/
function addEventListeners() {
eventsAreBound = true;
window.addEventListener( 'hashchange', onWindowHashChange, false );
window.addEventListener( 'resize', onWindowResize, false );
if( config.touch ) {
dom.wrapper.addEventListener( 'touchstart', onTouchStart, false );
dom.wrapper.addEventListener( 'touchmove', onTouchMove, false );
dom.wrapper.addEventListener( 'touchend', onTouchEnd, false );
// Support pointer-style touch interaction as well
if( window.navigator.msPointerEnabled ) {
dom.wrapper.addEventListener( 'MSPointerDown', onPointerDown, false );
dom.wrapper.addEventListener( 'MSPointerMove', onPointerMove, false );
dom.wrapper.addEventListener( 'MSPointerUp', onPointerUp, false );
}
if( config.keyboard ) {
document.addEventListener( 'keydown', onDocumentKeyDown, false );
}
if ( config.progress && dom.progress ) {

Hakim El Hattab
committed
dom.progress.addEventListener( 'click', onProgressClicked, 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 ); } );
} );

Hakim El Hattab
committed
/**
* Unbinds all event listeners.
*/
function removeEventListeners() {
eventsAreBound = false;
document.removeEventListener( 'keydown', onDocumentKeyDown, false );
window.removeEventListener( 'hashchange', onWindowHashChange, false );
window.removeEventListener( 'resize', onWindowResize, false );
dom.wrapper.removeEventListener( 'touchstart', onTouchStart, false );
dom.wrapper.removeEventListener( 'touchmove', onTouchMove, false );
dom.wrapper.removeEventListener( 'touchend', onTouchEnd, false );
if( window.navigator.msPointerEnabled ) {
dom.wrapper.removeEventListener( 'MSPointerDown', onPointerDown, false );
dom.wrapper.removeEventListener( 'MSPointerMove', onPointerMove, false );
dom.wrapper.removeEventListener( 'MSPointerUp', onPointerUp, false );
if ( config.progress && dom.progress ) {

Hakim El Hattab
committed
dom.progress.removeEventListener( 'click', onProgressClicked, false );
[ 'touchstart', 'click' ].forEach( function( eventName ) {
dom.controlsLeft.forEach( function( el ) {
Loading
Loading full blame...