annotate www/p/js/reveal.js @ 101:52e44ee1c791 tip master

enabled all scores in autostart script
author Rob Canning <rc@kiben.net>
date Tue, 21 Apr 2015 16:20:57 +0100
parents 49c94f63b8b0
children
rev   line source
rc-web@42 1 /*!
rc-web@42 2 * reveal.js 2.0 r22
rc-web@42 3 * http://lab.hakim.se/reveal-js
rc-web@42 4 * MIT licensed
rc-web@42 5 *
rc-web@42 6 * Copyright (C) 2011-2012 Hakim El Hattab, http://hakim.se
rc-web@42 7 */
rc-web@42 8 var Reveal = (function(){
rc-web@42 9
rc-web@42 10 var HORIZONTAL_SLIDES_SELECTOR = '.reveal .slides>section',
rc-web@42 11 VERTICAL_SLIDES_SELECTOR = '.reveal .slides>section.present>section',
rc-web@42 12
rc-web@42 13 IS_TOUCH_DEVICE = !!( 'ontouchstart' in window ),
rc-web@42 14
rc-web@42 15 // Configurations defaults, can be overridden at initialization time
rc-web@42 16 config = {
rc-web@42 17 // Display controls in the bottom right corner
rc-web@42 18 controls: true,
rc-web@42 19
rc-web@42 20 // Display a presentation progress bar
rc-web@42 21 progress: true,
rc-web@42 22
rc-web@42 23 // Push each slide change to the browser history
rc-web@42 24 history: false,
rc-web@42 25
rc-web@42 26 // Enable keyboard shortcuts for navigation
rc-web@42 27 keyboard: true,
rc-web@42 28
rc-web@42 29 // Loop the presentation
rc-web@42 30 loop: false,
rc-web@42 31
rc-web@42 32 // Number of milliseconds between automatically proceeding to the
rc-web@42 33 // next slide, disabled when set to 0
rc-web@42 34 autoSlide: 0,
rc-web@42 35
rc-web@42 36 // Enable slide navigation via mouse wheel
rc-web@42 37 mouseWheel: true,
rc-web@42 38
rc-web@42 39 // Apply a 3D roll to links on hover
rc-web@42 40 rollingLinks: true,
rc-web@42 41
rc-web@42 42 // Transition style (see /css/theme)
rc-web@42 43 theme: 'default',
rc-web@42 44
rc-web@42 45 // Transition style
rc-web@42 46 transition: 'default', // default/cube/page/concave/linear(2d),
rc-web@42 47
rc-web@42 48 // Script dependencies to load
rc-web@42 49 dependencies: []
rc-web@42 50 },
rc-web@42 51
rc-web@42 52 // The horizontal and verical index of the currently active slide
rc-web@42 53 indexh = 0,
rc-web@42 54 indexv = 0,
rc-web@42 55
rc-web@42 56 // The previous and current slide HTML elements
rc-web@42 57 previousSlide,
rc-web@42 58 currentSlide,
rc-web@42 59
rc-web@42 60 // Slides may hold a data-state attribute which we pick up and apply
rc-web@42 61 // as a class to the body. This list contains the combined state of
rc-web@42 62 // all current slides.
rc-web@42 63 state = [],
rc-web@42 64
rc-web@42 65 // Cached references to DOM elements
rc-web@42 66 dom = {},
rc-web@42 67
rc-web@42 68 // Detect support for CSS 3D transforms
rc-web@42 69 supports3DTransforms = 'WebkitPerspective' in document.body.style ||
rc-web@42 70 'MozPerspective' in document.body.style ||
rc-web@42 71 'msPerspective' in document.body.style ||
rc-web@42 72 'OPerspective' in document.body.style ||
rc-web@42 73 'perspective' in document.body.style,
rc-web@42 74
rc-web@42 75 supports2DTransforms = 'WebkitTransform' in document.body.style ||
rc-web@42 76 'MozTransform' in document.body.style ||
rc-web@42 77 'msTransform' in document.body.style ||
rc-web@42 78 'OTransform' in document.body.style ||
rc-web@42 79 'transform' in document.body.style,
rc-web@42 80
rc-web@42 81 // Throttles mouse wheel navigation
rc-web@42 82 mouseWheelTimeout = 0,
rc-web@42 83
rc-web@42 84 // An interval used to automatically move on to the next slide
rc-web@42 85 autoSlideTimeout = 0,
rc-web@42 86
rc-web@42 87 // Delays updates to the URL due to a Chrome thumbnailer bug
rc-web@42 88 writeURLTimeout = 0,
rc-web@42 89
rc-web@42 90 // Holds information about the currently ongoing touch input
rc-web@42 91 touch = {
rc-web@42 92 startX: 0,
rc-web@42 93 startY: 0,
rc-web@42 94 startSpan: 0,
rc-web@42 95 startCount: 0,
rc-web@42 96 handled: false,
rc-web@42 97 threshold: 40
rc-web@42 98 };
rc-web@42 99
rc-web@42 100
rc-web@42 101 /**
rc-web@42 102 * Starts up the presentation if the client is capable.
rc-web@42 103 */
rc-web@42 104 function initialize( options ) {
rc-web@42 105 if( ( !supports2DTransforms && !supports3DTransforms ) ) {
rc-web@42 106 document.body.setAttribute( 'class', 'no-transforms' );
rc-web@42 107
rc-web@42 108 // If the browser doesn't support core features we won't be
rc-web@42 109 // using JavaScript to control the presentation
rc-web@42 110 return;
rc-web@42 111 }
rc-web@42 112
rc-web@42 113 // Copy options over to our config object
rc-web@42 114 extend( config, options );
rc-web@42 115
rc-web@42 116 // Cache references to DOM elements
rc-web@42 117 dom.theme = document.querySelector( '#theme' );
rc-web@42 118 dom.wrapper = document.querySelector( '.reveal' );
rc-web@42 119 dom.progress = document.querySelector( '.reveal .progress' );
rc-web@42 120 dom.progressbar = document.querySelector( '.reveal .progress span' );
rc-web@42 121
rc-web@42 122 if ( config.controls ) {
rc-web@42 123 dom.controls = document.querySelector( '.reveal .controls' );
rc-web@42 124 dom.controlsLeft = document.querySelector( '.reveal .controls .left' );
rc-web@42 125 dom.controlsRight = document.querySelector( '.reveal .controls .right' );
rc-web@42 126 dom.controlsUp = document.querySelector( '.reveal .controls .up' );
rc-web@42 127 dom.controlsDown = document.querySelector( '.reveal .controls .down' );
rc-web@42 128 }
rc-web@42 129
rc-web@42 130 // Loads the dependencies and continues to #start() once done
rc-web@42 131 load();
rc-web@42 132
rc-web@42 133 // Set up hiding of the browser address bar
rc-web@42 134 if( navigator.userAgent.match( /(iphone|ipod|android)/i ) ) {
rc-web@42 135 // Give the page some scrollable overflow
rc-web@42 136 document.documentElement.style.overflow = 'scroll';
rc-web@42 137 document.body.style.height = '120%';
rc-web@42 138
rc-web@42 139 // Events that should trigger the address bar to hide
rc-web@42 140 window.addEventListener( 'load', removeAddressBar, false );
rc-web@42 141 window.addEventListener( 'orientationchange', removeAddressBar, false );
rc-web@42 142 }
rc-web@42 143
rc-web@42 144 }
rc-web@42 145
rc-web@42 146 /**
rc-web@42 147 * Loads the dependencies of reveal.js. Dependencies are
rc-web@42 148 * defined via the configuration option 'dependencies'
rc-web@42 149 * and will be loaded prior to starting/binding reveal.js.
rc-web@42 150 * Some dependencies may have an 'async' flag, if so they
rc-web@42 151 * will load after reveal.js has been started up.
rc-web@42 152 */
rc-web@42 153 function load() {
rc-web@42 154 var scripts = [],
rc-web@42 155 scriptsAsync = [];
rc-web@42 156
rc-web@42 157 for( var i = 0, len = config.dependencies.length; i < len; i++ ) {
rc-web@42 158 var s = config.dependencies[i];
rc-web@42 159
rc-web@42 160 // Load if there's no condition or the condition is truthy
rc-web@42 161 if( !s.condition || s.condition() ) {
rc-web@42 162 if( s.async ) {
rc-web@42 163 scriptsAsync.push( s.src );
rc-web@42 164 }
rc-web@42 165 else {
rc-web@42 166 scripts.push( s.src );
rc-web@42 167 }
rc-web@42 168
rc-web@42 169 // Extension may contain callback functions
rc-web@42 170 if( typeof s.callback === 'function' ) {
rc-web@42 171 head.ready( s.src.match( /([\w\d_-]*)\.?[^\\\/]*$/i )[0], s.callback );
rc-web@42 172 }
rc-web@42 173 }
rc-web@42 174 }
rc-web@42 175
rc-web@42 176 // Called once synchronous scritps finish loading
rc-web@42 177 function proceed() {
rc-web@42 178 // Load asynchronous scripts
rc-web@42 179 head.js.apply( null, scriptsAsync );
rc-web@42 180
rc-web@42 181 start();
rc-web@42 182 }
rc-web@42 183
rc-web@42 184 if( scripts.length ) {
rc-web@42 185 head.ready( proceed );
rc-web@42 186
rc-web@42 187 // Load synchronous scripts
rc-web@42 188 head.js.apply( null, scripts );
rc-web@42 189 }
rc-web@42 190 else {
rc-web@42 191 proceed();
rc-web@42 192 }
rc-web@42 193 }
rc-web@42 194
rc-web@42 195 /**
rc-web@42 196 * Starts up reveal.js by binding input events and navigating
rc-web@42 197 * to the current URL deeplink if there is one.
rc-web@42 198 */
rc-web@42 199 function start() {
rc-web@42 200 // Subscribe to input
rc-web@42 201 addEventListeners();
rc-web@42 202
rc-web@42 203 // Updates the presentation to match the current configuration values
rc-web@42 204 configure();
rc-web@42 205
rc-web@42 206 // Read the initial hash
rc-web@42 207 readURL();
rc-web@42 208
rc-web@42 209 // Start auto-sliding if it's enabled
rc-web@42 210 cueAutoSlide();
rc-web@42 211 }
rc-web@42 212
rc-web@42 213 /**
rc-web@42 214 * Applies the configuration settings from the config object.
rc-web@42 215 */
rc-web@42 216 function configure() {
rc-web@42 217 if( supports3DTransforms === false ) {
rc-web@42 218 config.transition = 'linear';
rc-web@42 219 }
rc-web@42 220
rc-web@42 221 if( config.controls && dom.controls ) {
rc-web@42 222 dom.controls.style.display = 'block';
rc-web@42 223 }
rc-web@42 224
rc-web@42 225 if( config.progress && dom.progress ) {
rc-web@42 226 dom.progress.style.display = 'block';
rc-web@42 227 }
rc-web@42 228
rc-web@42 229 // Load the theme in the config, if it's not already loaded
rc-web@42 230 if( config.theme && dom.theme ) {
rc-web@42 231 var themeURL = dom.theme.getAttribute( 'href' );
rc-web@42 232 var themeFinder = /[^/]*?(?=\.css)/;
rc-web@42 233 var themeName = themeURL.match(themeFinder)[0];
rc-web@42 234 if( config.theme !== themeName ) {
rc-web@42 235 themeURL = themeURL.replace(themeFinder, config.theme);
rc-web@42 236 dom.theme.setAttribute( 'href', themeURL );
rc-web@42 237 }
rc-web@42 238 }
rc-web@42 239
rc-web@42 240
rc-web@42 241 if( config.transition !== 'default' ) {
rc-web@42 242 dom.wrapper.classList.add( config.transition );
rc-web@42 243 }
rc-web@42 244
rc-web@42 245 if( config.mouseWheel ) {
rc-web@42 246 document.addEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF
rc-web@42 247 document.addEventListener( 'mousewheel', onDocumentMouseScroll, false );
rc-web@42 248 }
rc-web@42 249
rc-web@42 250 if( config.rollingLinks ) {
rc-web@42 251 // Add some 3D magic to our anchors
rc-web@42 252 linkify();
rc-web@42 253 }
rc-web@42 254 }
rc-web@42 255
rc-web@42 256 function addEventListeners() {
rc-web@42 257 document.addEventListener( 'touchstart', onDocumentTouchStart, false );
rc-web@42 258 document.addEventListener( 'touchmove', onDocumentTouchMove, false );
rc-web@42 259 document.addEventListener( 'touchend', onDocumentTouchEnd, false );
rc-web@42 260 window.addEventListener( 'hashchange', onWindowHashChange, false );
rc-web@42 261
rc-web@42 262 if( config.keyboard ) {
rc-web@42 263 document.addEventListener( 'keydown', onDocumentKeyDown, false );
rc-web@42 264 }
rc-web@42 265
rc-web@42 266 if ( config.controls && dom.controls ) {
rc-web@42 267 dom.controlsLeft.addEventListener( 'click', preventAndForward( navigateLeft ), false );
rc-web@42 268 dom.controlsRight.addEventListener( 'click', preventAndForward( navigateRight ), false );
rc-web@42 269 dom.controlsUp.addEventListener( 'click', preventAndForward( navigateUp ), false );
rc-web@42 270 dom.controlsDown.addEventListener( 'click', preventAndForward( navigateDown ), false );
rc-web@42 271 }
rc-web@42 272 }
rc-web@42 273
rc-web@42 274 function removeEventListeners() {
rc-web@42 275 document.removeEventListener( 'keydown', onDocumentKeyDown, false );
rc-web@42 276 document.removeEventListener( 'touchstart', onDocumentTouchStart, false );
rc-web@42 277 document.removeEventListener( 'touchmove', onDocumentTouchMove, false );
rc-web@42 278 document.removeEventListener( 'touchend', onDocumentTouchEnd, false );
rc-web@42 279 window.removeEventListener( 'hashchange', onWindowHashChange, false );
rc-web@42 280
rc-web@42 281 if ( config.controls && dom.controls ) {
rc-web@42 282 dom.controlsLeft.removeEventListener( 'click', preventAndForward( navigateLeft ), false );
rc-web@42 283 dom.controlsRight.removeEventListener( 'click', preventAndForward( navigateRight ), false );
rc-web@42 284 dom.controlsUp.removeEventListener( 'click', preventAndForward( navigateUp ), false );
rc-web@42 285 dom.controlsDown.removeEventListener( 'click', preventAndForward( navigateDown ), false );
rc-web@42 286 }
rc-web@42 287 }
rc-web@42 288
rc-web@42 289 /**
rc-web@42 290 * Extend object a with the properties of object b.
rc-web@42 291 * If there's a conflict, object b takes precedence.
rc-web@42 292 */
rc-web@42 293 function extend( a, b ) {
rc-web@42 294 for( var i in b ) {
rc-web@42 295 a[ i ] = b[ i ];
rc-web@42 296 }
rc-web@42 297 }
rc-web@42 298
rc-web@42 299 /**
rc-web@42 300 * Measures the distance in pixels between point a
rc-web@42 301 * and point b.
rc-web@42 302 *
rc-web@42 303 * @param {Object} a point with x/y properties
rc-web@42 304 * @param {Object} b point with x/y properties
rc-web@42 305 */
rc-web@42 306 function distanceBetween( a, b ) {
rc-web@42 307 var dx = a.x - b.x,
rc-web@42 308 dy = a.y - b.y;
rc-web@42 309
rc-web@42 310 return Math.sqrt( dx*dx + dy*dy );
rc-web@42 311 }
rc-web@42 312
rc-web@42 313 /**
rc-web@42 314 * Prevents an events defaults behavior calls the
rc-web@42 315 * specified delegate.
rc-web@42 316 *
rc-web@42 317 * @param {Function} delegate The method to call
rc-web@42 318 * after the wrapper has been executed
rc-web@42 319 */
rc-web@42 320 function preventAndForward( delegate ) {
rc-web@42 321 return function( event ) {
rc-web@42 322 event.preventDefault();
rc-web@42 323 delegate.call();
rc-web@42 324 }
rc-web@42 325 }
rc-web@42 326
rc-web@42 327 /**
rc-web@42 328 * Causes the address bar to hide on mobile devices,
rc-web@42 329 * more vertical space ftw.
rc-web@42 330 */
rc-web@42 331 function removeAddressBar() {
rc-web@42 332 setTimeout( function() {
rc-web@42 333 window.scrollTo( 0, 1 );
rc-web@42 334 }, 0 );
rc-web@42 335 }
rc-web@42 336
rc-web@42 337 /**
rc-web@42 338 * Handler for the document level 'keydown' event.
rc-web@42 339 *
rc-web@42 340 * @param {Object} event
rc-web@42 341 */
rc-web@42 342 function onDocumentKeyDown( event ) {
rc-web@42 343 // FFT: Use document.querySelector( ':focus' ) === null
rc-web@42 344 // instead of checking contentEditable?
rc-web@42 345
rc-web@42 346 // Disregard the event if the target is editable or a
rc-web@42 347 // modifier is present
rc-web@42 348 if ( event.target.contentEditable != 'inherit' || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return;
rc-web@42 349
rc-web@42 350 var triggered = false;
rc-web@42 351
rc-web@42 352 switch( event.keyCode ) {
rc-web@42 353 // p, page up
rc-web@42 354 case 80: case 33: navigatePrev(); triggered = true; break;
rc-web@42 355 // n, page down
rc-web@42 356 case 78: case 34: navigateNext(); triggered = true; break;
rc-web@42 357 // h, left
rc-web@42 358 case 72: case 37: navigateLeft(); triggered = true; break;
rc-web@42 359 // l, right
rc-web@42 360 case 76: case 39: navigateRight(); triggered = true; break;
rc-web@42 361 // k, up
rc-web@42 362 case 75: case 38: navigateUp(); triggered = true; break;
rc-web@42 363 // j, down
rc-web@42 364 case 74: case 40: navigateDown(); triggered = true; break;
rc-web@42 365 // home
rc-web@42 366 case 36: navigateTo( 0 ); triggered = true; break;
rc-web@42 367 // end
rc-web@42 368 case 35: navigateTo( Number.MAX_VALUE ); triggered = true; break;
rc-web@42 369 // space
rc-web@42 370 case 32: overviewIsActive() ? deactivateOverview() : navigateNext(); triggered = true; break;
rc-web@42 371 // return
rc-web@42 372 case 13: if( overviewIsActive() ) { deactivateOverview(); triggered = true; } break;
rc-web@42 373 }
rc-web@42 374
rc-web@42 375 // If the input resulted in a triggered action we should prevent
rc-web@42 376 // the browsers default behavior
rc-web@42 377 if( triggered ) {
rc-web@42 378 event.preventDefault();
rc-web@42 379 }
rc-web@42 380 else if ( event.keyCode === 27 && supports3DTransforms ) {
rc-web@42 381 toggleOverview();
rc-web@42 382
rc-web@42 383 event.preventDefault();
rc-web@42 384 }
rc-web@42 385
rc-web@42 386 // If auto-sliding is enabled we need to cue up
rc-web@42 387 // another timeout
rc-web@42 388 cueAutoSlide();
rc-web@42 389
rc-web@42 390 }
rc-web@42 391
rc-web@42 392 /**
rc-web@42 393 * Handler for the document level 'touchstart' event,
rc-web@42 394 * enables support for swipe and pinch gestures.
rc-web@42 395 */
rc-web@42 396 function onDocumentTouchStart( event ) {
rc-web@42 397 touch.startX = event.touches[0].clientX;
rc-web@42 398 touch.startY = event.touches[0].clientY;
rc-web@42 399 touch.startCount = event.touches.length;
rc-web@42 400
rc-web@42 401 // If there's two touches we need to memorize the distance
rc-web@42 402 // between those two points to detect pinching
rc-web@42 403 if( event.touches.length === 2 ) {
rc-web@42 404 touch.startSpan = distanceBetween( {
rc-web@42 405 x: event.touches[1].clientX,
rc-web@42 406 y: event.touches[1].clientY
rc-web@42 407 }, {
rc-web@42 408 x: touch.startX,
rc-web@42 409 y: touch.startY
rc-web@42 410 } );
rc-web@42 411 }
rc-web@42 412 }
rc-web@42 413
rc-web@42 414 /**
rc-web@42 415 * Handler for the document level 'touchmove' event.
rc-web@42 416 */
rc-web@42 417 function onDocumentTouchMove( event ) {
rc-web@42 418 // Each touch should only trigger one action
rc-web@42 419 if( !touch.handled ) {
rc-web@42 420 var currentX = event.touches[0].clientX;
rc-web@42 421 var currentY = event.touches[0].clientY;
rc-web@42 422
rc-web@42 423 // If the touch started off with two points and still has
rc-web@42 424 // two active touches; test for the pinch gesture
rc-web@42 425 if( event.touches.length === 2 && touch.startCount === 2 ) {
rc-web@42 426
rc-web@42 427 // The current distance in pixels between the two touch points
rc-web@42 428 var currentSpan = distanceBetween( {
rc-web@42 429 x: event.touches[1].clientX,
rc-web@42 430 y: event.touches[1].clientY
rc-web@42 431 }, {
rc-web@42 432 x: touch.startX,
rc-web@42 433 y: touch.startY
rc-web@42 434 } );
rc-web@42 435
rc-web@42 436 // If the span is larger than the desire amount we've got
rc-web@42 437 // ourselves a pinch
rc-web@42 438 if( Math.abs( touch.startSpan - currentSpan ) > touch.threshold ) {
rc-web@42 439 touch.handled = true;
rc-web@42 440
rc-web@42 441 if( currentSpan < touch.startSpan ) {
rc-web@42 442 activateOverview();
rc-web@42 443 }
rc-web@42 444 else {
rc-web@42 445 deactivateOverview();
rc-web@42 446 }
rc-web@42 447 }
rc-web@42 448
rc-web@42 449 }
rc-web@42 450 // There was only one touch point, look for a swipe
rc-web@42 451 else if( event.touches.length === 1 ) {
rc-web@42 452 var deltaX = currentX - touch.startX,
rc-web@42 453 deltaY = currentY - touch.startY;
rc-web@42 454
rc-web@42 455 if( deltaX > touch.threshold && Math.abs( deltaX ) > Math.abs( deltaY ) ) {
rc-web@42 456 touch.handled = true;
rc-web@42 457 navigateLeft();
rc-web@42 458 }
rc-web@42 459 else if( deltaX < -touch.threshold && Math.abs( deltaX ) > Math.abs( deltaY ) ) {
rc-web@42 460 touch.handled = true;
rc-web@42 461 navigateRight();
rc-web@42 462 }
rc-web@42 463 else if( deltaY > touch.threshold ) {
rc-web@42 464 touch.handled = true;
rc-web@42 465 navigateUp();
rc-web@42 466 }
rc-web@42 467 else if( deltaY < -touch.threshold ) {
rc-web@42 468 touch.handled = true;
rc-web@42 469 navigateDown();
rc-web@42 470 }
rc-web@42 471 }
rc-web@42 472
rc-web@42 473 event.preventDefault();
rc-web@42 474 }
rc-web@42 475 }
rc-web@42 476
rc-web@42 477 /**
rc-web@42 478 * Handler for the document level 'touchend' event.
rc-web@42 479 */
rc-web@42 480 function onDocumentTouchEnd( event ) {
rc-web@42 481 touch.handled = false;
rc-web@42 482 }
rc-web@42 483
rc-web@42 484 /**
rc-web@42 485 * Handles mouse wheel scrolling, throttled to avoid
rc-web@42 486 * skipping multiple slides.
rc-web@42 487 */
rc-web@42 488 function onDocumentMouseScroll( event ){
rc-web@42 489 clearTimeout( mouseWheelTimeout );
rc-web@42 490
rc-web@42 491 mouseWheelTimeout = setTimeout( function() {
rc-web@42 492 var delta = event.detail || -event.wheelDelta;
rc-web@42 493 if( delta > 0 ) {
rc-web@42 494 navigateNext();
rc-web@42 495 }
rc-web@42 496 else {
rc-web@42 497 navigatePrev();
rc-web@42 498 }
rc-web@42 499 }, 100 );
rc-web@42 500 }
rc-web@42 501
rc-web@42 502 /**
rc-web@42 503 * Handler for the window level 'hashchange' event.
rc-web@42 504 *
rc-web@42 505 * @param {Object} event
rc-web@42 506 */
rc-web@42 507 function onWindowHashChange( event ) {
rc-web@42 508 readURL();
rc-web@42 509 }
rc-web@42 510
rc-web@42 511 /**
rc-web@42 512 * Wrap all links in 3D goodness.
rc-web@42 513 */
rc-web@42 514 function linkify() {
rc-web@42 515 if( supports3DTransforms && !( 'msPerspective' in document.body.style ) ) {
rc-web@42 516 var nodes = document.querySelectorAll( '.reveal .slides section a:not(.image)' );
rc-web@42 517
rc-web@42 518 for( var i = 0, len = nodes.length; i < len; i++ ) {
rc-web@42 519 var node = nodes[i];
rc-web@42 520
rc-web@42 521 if( node.textContent && !node.querySelector( 'img' ) && ( !node.className || !node.classList.contains( node, 'roll' ) ) ) {
rc-web@42 522 node.classList.add( 'roll' );
rc-web@42 523 node.innerHTML = '<span data-title="'+ node.text +'">' + node.innerHTML + '</span>';
rc-web@42 524 }
rc-web@42 525 };
rc-web@42 526 }
rc-web@42 527 }
rc-web@42 528
rc-web@42 529 /**
rc-web@42 530 * Displays the overview of slides (quick nav) by
rc-web@42 531 * scaling down and arranging all slide elements.
rc-web@42 532 *
rc-web@42 533 * Experimental feature, might be dropped if perf
rc-web@42 534 * can't be improved.
rc-web@42 535 */
rc-web@42 536 function activateOverview() {
rc-web@42 537
rc-web@42 538 dom.wrapper.classList.add( 'overview' );
rc-web@42 539
rc-web@42 540 var horizontalSlides = Array.prototype.slice.call( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) );
rc-web@42 541
rc-web@42 542 for( var i = 0, len1 = horizontalSlides.length; i < len1; i++ ) {
rc-web@42 543 var hslide = horizontalSlides[i],
rc-web@42 544 htransform = 'translateZ(-2500px) translate(' + ( ( i - indexh ) * 105 ) + '%, 0%)';
rc-web@42 545
rc-web@42 546 hslide.setAttribute( 'data-index-h', i );
rc-web@42 547 hslide.style.display = 'block';
rc-web@42 548 hslide.style.WebkitTransform = htransform;
rc-web@42 549 hslide.style.MozTransform = htransform;
rc-web@42 550 hslide.style.msTransform = htransform;
rc-web@42 551 hslide.style.OTransform = htransform;
rc-web@42 552 hslide.style.transform = htransform;
rc-web@42 553
rc-web@42 554 if( !hslide.classList.contains( 'stack' ) ) {
rc-web@42 555 // Navigate to this slide on click
rc-web@42 556 hslide.addEventListener( 'click', onOverviewSlideClicked, true );
rc-web@42 557 }
rc-web@42 558
rc-web@42 559 var verticalSlides = Array.prototype.slice.call( hslide.querySelectorAll( 'section' ) );
rc-web@42 560
rc-web@42 561 for( var j = 0, len2 = verticalSlides.length; j < len2; j++ ) {
rc-web@42 562 var vslide = verticalSlides[j],
rc-web@42 563 vtransform = 'translate(0%, ' + ( ( j - ( i === indexh ? indexv : 0 ) ) * 105 ) + '%)';
rc-web@42 564
rc-web@42 565 vslide.setAttribute( 'data-index-h', i );
rc-web@42 566 vslide.setAttribute( 'data-index-v', j );
rc-web@42 567 vslide.style.display = 'block';
rc-web@42 568 vslide.style.WebkitTransform = vtransform;
rc-web@42 569 vslide.style.MozTransform = vtransform;
rc-web@42 570 vslide.style.msTransform = vtransform;
rc-web@42 571 vslide.style.OTransform = vtransform;
rc-web@42 572 vslide.style.transform = vtransform;
rc-web@42 573
rc-web@42 574 // Navigate to this slide on click
rc-web@42 575 vslide.addEventListener( 'click', onOverviewSlideClicked, true );
rc-web@42 576 }
rc-web@42 577
rc-web@42 578 }
rc-web@42 579 }
rc-web@42 580
rc-web@42 581 /**
rc-web@42 582 * Exits the slide overview and enters the currently
rc-web@42 583 * active slide.
rc-web@42 584 */
rc-web@42 585 function deactivateOverview() {
rc-web@42 586 dom.wrapper.classList.remove( 'overview' );
rc-web@42 587
rc-web@42 588 var slides = Array.prototype.slice.call( document.querySelectorAll( '.reveal .slides section' ) );
rc-web@42 589
rc-web@42 590 for( var i = 0, len = slides.length; i < len; i++ ) {
rc-web@42 591 var element = slides[i];
rc-web@42 592
rc-web@42 593 // Resets all transforms to use the external styles
rc-web@42 594 element.style.WebkitTransform = '';
rc-web@42 595 element.style.MozTransform = '';
rc-web@42 596 element.style.msTransform = '';
rc-web@42 597 element.style.OTransform = '';
rc-web@42 598 element.style.transform = '';
rc-web@42 599
rc-web@42 600 element.removeEventListener( 'click', onOverviewSlideClicked );
rc-web@42 601 }
rc-web@42 602
rc-web@42 603 slide();
rc-web@42 604 }
rc-web@42 605
rc-web@42 606 /**
rc-web@42 607 * Checks if the overview is currently active.
rc-web@42 608 *
rc-web@42 609 * @return {Boolean} true if the overview is active,
rc-web@42 610 * false otherwise
rc-web@42 611 */
rc-web@42 612 function overviewIsActive() {
rc-web@42 613 return dom.wrapper.classList.contains( 'overview' );
rc-web@42 614 }
rc-web@42 615
rc-web@42 616 /**
rc-web@42 617 * Invoked when a slide is and we're in the overview.
rc-web@42 618 */
rc-web@42 619 function onOverviewSlideClicked( event ) {
rc-web@42 620 // TODO There's a bug here where the event listeners are not
rc-web@42 621 // removed after deactivating the overview.
rc-web@42 622 if( overviewIsActive() ) {
rc-web@42 623 event.preventDefault();
rc-web@42 624
rc-web@42 625 deactivateOverview();
rc-web@42 626
rc-web@42 627 indexh = this.getAttribute( 'data-index-h' );
rc-web@42 628 indexv = this.getAttribute( 'data-index-v' );
rc-web@42 629
rc-web@42 630 slide();
rc-web@42 631 }
rc-web@42 632 }
rc-web@42 633
rc-web@42 634 /**
rc-web@42 635 * Updates one dimension of slides by showing the slide
rc-web@42 636 * with the specified index.
rc-web@42 637 *
rc-web@42 638 * @param {String} selector A CSS selector that will fetch
rc-web@42 639 * the group of slides we are working with
rc-web@42 640 * @param {Number} index The index of the slide that should be
rc-web@42 641 * shown
rc-web@42 642 *
rc-web@42 643 * @return {Number} The index of the slide that is now shown,
rc-web@42 644 * might differ from the passed in index if it was out of
rc-web@42 645 * bounds.
rc-web@42 646 */
rc-web@42 647 function updateSlides( selector, index ) {
rc-web@42 648
rc-web@42 649 // Select all slides and convert the NodeList result to
rc-web@42 650 // an array
rc-web@42 651 var slides = Array.prototype.slice.call( document.querySelectorAll( selector ) ),
rc-web@42 652 slidesLength = slides.length;
rc-web@42 653
rc-web@42 654 if( slidesLength ) {
rc-web@42 655
rc-web@42 656 // Should the index loop?
rc-web@42 657 if( config.loop ) {
rc-web@42 658 index %= slidesLength;
rc-web@42 659
rc-web@42 660 if( index < 0 ) {
rc-web@42 661 index = slidesLength + index;
rc-web@42 662 }
rc-web@42 663 }
rc-web@42 664
rc-web@42 665 // Enforce max and minimum index bounds
rc-web@42 666 index = Math.max( Math.min( index, slidesLength - 1 ), 0 );
rc-web@42 667
rc-web@42 668 for( var i = 0; i < slidesLength; i++ ) {
rc-web@42 669 var slide = slides[i];
rc-web@42 670
rc-web@42 671 // Optimization; hide all slides that are three or more steps
rc-web@42 672 // away from the present slide
rc-web@42 673 if( overviewIsActive() === false ) {
rc-web@42 674 // The distance loops so that it measures 1 between the first
rc-web@42 675 // and last slides
rc-web@42 676 var distance = Math.abs( ( index - i ) % ( slidesLength - 3 ) ) || 0;
rc-web@42 677
rc-web@42 678 slide.style.display = distance > 3 ? 'none' : 'block';
rc-web@42 679 }
rc-web@42 680
rc-web@42 681 slides[i].classList.remove( 'past' );
rc-web@42 682 slides[i].classList.remove( 'present' );
rc-web@42 683 slides[i].classList.remove( 'future' );
rc-web@42 684
rc-web@42 685 if( i < index ) {
rc-web@42 686 // Any element previous to index is given the 'past' class
rc-web@42 687 slides[i].classList.add( 'past' );
rc-web@42 688 }
rc-web@42 689 else if( i > index ) {
rc-web@42 690 // Any element subsequent to index is given the 'future' class
rc-web@42 691 slides[i].classList.add( 'future' );
rc-web@42 692 }
rc-web@42 693
rc-web@42 694 // If this element contains vertical slides
rc-web@42 695 if( slide.querySelector( 'section' ) ) {
rc-web@42 696 slides[i].classList.add( 'stack' );
rc-web@42 697 }
rc-web@42 698 }
rc-web@42 699
rc-web@42 700 // Mark the current slide as present
rc-web@42 701 slides[index].classList.add( 'present' );
rc-web@42 702
rc-web@42 703 // If this slide has a state associated with it, add it
rc-web@42 704 // onto the current state of the deck
rc-web@42 705 var slideState = slides[index].getAttribute( 'data-state' );
rc-web@42 706 if( slideState ) {
rc-web@42 707 state = state.concat( slideState.split( ' ' ) );
rc-web@42 708 }
rc-web@42 709 }
rc-web@42 710 else {
rc-web@42 711 // Since there are no slides we can't be anywhere beyond the
rc-web@42 712 // zeroth index
rc-web@42 713 index = 0;
rc-web@42 714 }
rc-web@42 715
rc-web@42 716 return index;
rc-web@42 717
rc-web@42 718 }
rc-web@42 719
rc-web@42 720 /**
rc-web@42 721 * Updates the visual slides to represent the currently
rc-web@42 722 * set indices.
rc-web@42 723 */
rc-web@42 724 function slide( h, v ) {
rc-web@42 725 // Remember where we were at before
rc-web@42 726 previousSlide = currentSlide;
rc-web@42 727
rc-web@42 728 // Remember the state before this slide
rc-web@42 729 var stateBefore = state.concat();
rc-web@42 730
rc-web@42 731 // Reset the state array
rc-web@42 732 state.length = 0;
rc-web@42 733
rc-web@42 734 var indexhBefore = indexh,
rc-web@42 735 indexvBefore = indexv;
rc-web@42 736
rc-web@42 737 // Activate and transition to the new slide
rc-web@42 738 indexh = updateSlides( HORIZONTAL_SLIDES_SELECTOR, h === undefined ? indexh : h );
rc-web@42 739 indexv = updateSlides( VERTICAL_SLIDES_SELECTOR, v === undefined ? indexv : v );
rc-web@42 740
rc-web@42 741 // Apply the new state
rc-web@42 742 stateLoop: for( var i = 0, len = state.length; i < len; i++ ) {
rc-web@42 743 // Check if this state existed on the previous slide. If it
rc-web@42 744 // did, we will avoid adding it repeatedly.
rc-web@42 745 for( var j = 0; j < stateBefore.length; j++ ) {
rc-web@42 746 if( stateBefore[j] === state[i] ) {
rc-web@42 747 stateBefore.splice( j, 1 );
rc-web@42 748 continue stateLoop;
rc-web@42 749 }
rc-web@42 750 }
rc-web@42 751
rc-web@42 752 document.documentElement.classList.add( state[i] );
rc-web@42 753
rc-web@42 754 // Dispatch custom event matching the state's name
rc-web@42 755 dispatchEvent( state[i] );
rc-web@42 756 }
rc-web@42 757
rc-web@42 758 // Clean up the remaints of the previous state
rc-web@42 759 while( stateBefore.length ) {
rc-web@42 760 document.documentElement.classList.remove( stateBefore.pop() );
rc-web@42 761 }
rc-web@42 762
rc-web@42 763 // Update progress if enabled
rc-web@42 764 if( config.progress && dom.progress ) {
rc-web@42 765 dom.progressbar.style.width = ( indexh / ( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ).length - 1 ) ) * window.innerWidth + 'px';
rc-web@42 766 }
rc-web@42 767
rc-web@42 768 // Close the overview if it's active
rc-web@42 769 if( overviewIsActive() ) {
rc-web@42 770 activateOverview();
rc-web@42 771 }
rc-web@42 772
rc-web@42 773 updateControls();
rc-web@42 774
rc-web@42 775 clearTimeout( writeURLTimeout );
rc-web@42 776 writeURLTimeout = setTimeout( writeURL, 1500 );
rc-web@42 777
rc-web@42 778 // Query all horizontal slides in the deck
rc-web@42 779 var horizontalSlides = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR );
rc-web@42 780
rc-web@42 781 // Find the current horizontal slide and any possible vertical slides
rc-web@42 782 // within it
rc-web@42 783 var currentHorizontalSlide = horizontalSlides[ indexh ],
rc-web@42 784 currentVerticalSlides = currentHorizontalSlide.querySelectorAll( 'section' );
rc-web@42 785
rc-web@42 786 // Store references to the previous and current slides
rc-web@42 787 currentSlide = currentVerticalSlides[ indexv ] || currentHorizontalSlide;
rc-web@42 788
rc-web@42 789 // Dispatch an event if the slide changed
rc-web@42 790 if( indexh !== indexhBefore || indexv !== indexvBefore ) {
rc-web@42 791 dispatchEvent( 'slidechanged', {
rc-web@42 792 'indexh': indexh,
rc-web@42 793 'indexv': indexv,
rc-web@42 794 'previousSlide': previousSlide,
rc-web@42 795 'currentSlide': currentSlide
rc-web@42 796 } );
rc-web@42 797 }
rc-web@42 798 else {
rc-web@42 799 // Ensure that the previous slide is never the same as the current
rc-web@42 800 previousSlide = null;
rc-web@42 801 }
rc-web@42 802
rc-web@42 803 // Solves an edge case where the previous slide maintains the
rc-web@42 804 // 'present' class when navigating between adjacent vertical
rc-web@42 805 // stacks
rc-web@42 806 if( previousSlide ) {
rc-web@42 807 previousSlide.classList.remove( 'present' );
rc-web@42 808 }
rc-web@42 809 }
rc-web@42 810
rc-web@42 811 /**
rc-web@42 812 * Updates the state and link pointers of the controls.
rc-web@42 813 */
rc-web@42 814 function updateControls() {
rc-web@42 815 if ( !config.controls || !dom.controls ) {
rc-web@42 816 return;
rc-web@42 817 }
rc-web@42 818
rc-web@42 819 var routes = availableRoutes();
rc-web@42 820
rc-web@42 821 // Remove the 'enabled' class from all directions
rc-web@42 822 [ dom.controlsLeft, dom.controlsRight, dom.controlsUp, dom.controlsDown ].forEach( function( node ) {
rc-web@42 823 node.classList.remove( 'enabled' );
rc-web@42 824 } )
rc-web@42 825
rc-web@42 826 if( routes.left ) dom.controlsLeft.classList.add( 'enabled' );
rc-web@42 827 if( routes.right ) dom.controlsRight.classList.add( 'enabled' );
rc-web@42 828 if( routes.up ) dom.controlsUp.classList.add( 'enabled' );
rc-web@42 829 if( routes.down ) dom.controlsDown.classList.add( 'enabled' );
rc-web@42 830 }
rc-web@42 831
rc-web@42 832 /**
rc-web@42 833 * Determine what available routes there are for navigation.
rc-web@42 834 *
rc-web@42 835 * @return {Object} containing four booleans: left/right/up/down
rc-web@42 836 */
rc-web@42 837 function availableRoutes() {
rc-web@42 838 var horizontalSlides = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR );
rc-web@42 839 var verticalSlides = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR );
rc-web@42 840
rc-web@42 841 return {
rc-web@42 842 left: indexh > 0,
rc-web@42 843 right: indexh < horizontalSlides.length - 1,
rc-web@42 844 up: indexv > 0,
rc-web@42 845 down: indexv < verticalSlides.length - 1
rc-web@42 846 };
rc-web@42 847 }
rc-web@42 848
rc-web@42 849 /**
rc-web@42 850 * Reads the current URL (hash) and navigates accordingly.
rc-web@42 851 */
rc-web@42 852 function readURL() {
rc-web@42 853 var hash = window.location.hash;
rc-web@42 854
rc-web@42 855 // Attempt to parse the hash as either an index or name
rc-web@42 856 var bits = hash.slice( 2 ).split( '/' ),
rc-web@42 857 name = hash.replace( /#|\//gi, '' );
rc-web@42 858
rc-web@42 859 // If the first bit is invalid and there is a name we can
rc-web@42 860 // assume that this is a named link
rc-web@42 861 if( isNaN( parseInt( bits[0] ) ) && name.length ) {
rc-web@42 862 // Find the slide with the specified name
rc-web@42 863 var slide = document.querySelector( '#' + name );
rc-web@42 864
rc-web@42 865 if( slide ) {
rc-web@42 866 // Find the position of the named slide and navigate to it
rc-web@42 867 var indices = Reveal.getIndices( slide );
rc-web@42 868 navigateTo( indices.h, indices.v );
rc-web@42 869 }
rc-web@42 870 // If the slide doesn't exist, navigate to the current slide
rc-web@42 871 else {
rc-web@42 872 navigateTo( indexh, indexv );
rc-web@42 873 }
rc-web@42 874 }
rc-web@42 875 else {
rc-web@42 876 // Read the index components of the hash
rc-web@42 877 var h = parseInt( bits[0] ) || 0,
rc-web@42 878 v = parseInt( bits[1] ) || 0;
rc-web@42 879
rc-web@42 880 navigateTo( h, v );
rc-web@42 881 }
rc-web@42 882 }
rc-web@42 883
rc-web@42 884 /**
rc-web@42 885 * Updates the page URL (hash) to reflect the current
rc-web@42 886 * state.
rc-web@42 887 */
rc-web@42 888 function writeURL() {
rc-web@42 889 if( config.history ) {
rc-web@42 890 var url = '/';
rc-web@42 891
rc-web@42 892 // Only include the minimum possible number of components in
rc-web@42 893 // the URL
rc-web@42 894 if( indexh > 0 || indexv > 0 ) url += indexh;
rc-web@42 895 if( indexv > 0 ) url += '/' + indexv;
rc-web@42 896
rc-web@42 897 window.location.hash = url;
rc-web@42 898 }
rc-web@42 899 }
rc-web@42 900
rc-web@42 901 /**
rc-web@42 902 * Dispatches an event of the specified type from the
rc-web@42 903 * reveal DOM element.
rc-web@42 904 */
rc-web@42 905 function dispatchEvent( type, properties ) {
rc-web@42 906 var event = document.createEvent( "HTMLEvents", 1, 2 );
rc-web@42 907 event.initEvent( type, true, true );
rc-web@42 908 extend( event, properties );
rc-web@42 909 dom.wrapper.dispatchEvent( event );
rc-web@42 910 }
rc-web@42 911
rc-web@42 912 /**
rc-web@42 913 * Navigate to the next slide fragment.
rc-web@42 914 *
rc-web@42 915 * @return {Boolean} true if there was a next fragment,
rc-web@42 916 * false otherwise
rc-web@42 917 */
rc-web@42 918 function nextFragment() {
rc-web@42 919 // Vertical slides:
rc-web@42 920 if( document.querySelector( VERTICAL_SLIDES_SELECTOR + '.present' ) ) {
rc-web@42 921 var verticalFragments = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR + '.present .fragment:not(.visible)' );
rc-web@42 922 if( verticalFragments.length ) {
rc-web@42 923 verticalFragments[0].classList.add( 'visible' );
rc-web@42 924
rc-web@42 925 // Notify subscribers of the change
rc-web@42 926 dispatchEvent( 'fragmentshown', { fragment: verticalFragments[0] } );
rc-web@42 927 return true;
rc-web@42 928 }
rc-web@42 929 }
rc-web@42 930 // Horizontal slides:
rc-web@42 931 else {
rc-web@42 932 var horizontalFragments = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.present .fragment:not(.visible)' );
rc-web@42 933 if( horizontalFragments.length ) {
rc-web@42 934 horizontalFragments[0].classList.add( 'visible' );
rc-web@42 935
rc-web@42 936 // Notify subscribers of the change
rc-web@42 937 dispatchEvent( 'fragmentshown', { fragment: horizontalFragments[0] } );
rc-web@42 938 return true;
rc-web@42 939 }
rc-web@42 940 }
rc-web@42 941
rc-web@42 942 return false;
rc-web@42 943 }
rc-web@42 944
rc-web@42 945 /**
rc-web@42 946 * Navigate to the previous slide fragment.
rc-web@42 947 *
rc-web@42 948 * @return {Boolean} true if there was a previous fragment,
rc-web@42 949 * false otherwise
rc-web@42 950 */
rc-web@42 951 function previousFragment() {
rc-web@42 952 // Vertical slides:
rc-web@42 953 if( document.querySelector( VERTICAL_SLIDES_SELECTOR + '.present' ) ) {
rc-web@42 954 var verticalFragments = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR + '.present .fragment.visible' );
rc-web@42 955 if( verticalFragments.length ) {
rc-web@42 956 verticalFragments[ verticalFragments.length - 1 ].classList.remove( 'visible' );
rc-web@42 957
rc-web@42 958 // Notify subscribers of the change
rc-web@42 959 dispatchEvent( 'fragmenthidden', { fragment: verticalFragments[ verticalFragments.length - 1 ] } );
rc-web@42 960 return true;
rc-web@42 961 }
rc-web@42 962 }
rc-web@42 963 // Horizontal slides:
rc-web@42 964 else {
rc-web@42 965 var horizontalFragments = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.present .fragment.visible' );
rc-web@42 966 if( horizontalFragments.length ) {
rc-web@42 967 horizontalFragments[ horizontalFragments.length - 1 ].classList.remove( 'visible' );
rc-web@42 968
rc-web@42 969 // Notify subscribers of the change
rc-web@42 970 dispatchEvent( 'fragmenthidden', { fragment: horizontalFragments[ horizontalFragments.length - 1 ] } );
rc-web@42 971 return true;
rc-web@42 972 }
rc-web@42 973 }
rc-web@42 974
rc-web@42 975 return false;
rc-web@42 976 }
rc-web@42 977
rc-web@42 978 function cueAutoSlide() {
rc-web@42 979 clearTimeout( autoSlideTimeout );
rc-web@42 980
rc-web@42 981 // Cue the next auto-slide if enabled
rc-web@42 982 if( config.autoSlide ) {
rc-web@42 983 autoSlideTimeout = setTimeout( navigateNext, config.autoSlide );
rc-web@42 984 }
rc-web@42 985 }
rc-web@42 986
rc-web@42 987 /**
rc-web@42 988 * Triggers a navigation to the specified indices.
rc-web@42 989 *
rc-web@42 990 * @param {Number} h The horizontal index of the slide to show
rc-web@42 991 * @param {Number} v The vertical index of the slide to show
rc-web@42 992 */
rc-web@42 993 function navigateTo( h, v ) {
rc-web@42 994 slide( h, v );
rc-web@42 995 }
rc-web@42 996
rc-web@42 997 function navigateLeft() {
rc-web@42 998 // Prioritize hiding fragments
rc-web@42 999 if( overviewIsActive() || previousFragment() === false ) {
rc-web@42 1000 slide( indexh - 1, 0 );
rc-web@42 1001 }
rc-web@42 1002 }
rc-web@42 1003 function navigateRight() {
rc-web@42 1004 // Prioritize revealing fragments
rc-web@42 1005 if( overviewIsActive() || nextFragment() === false ) {
rc-web@42 1006 slide( indexh + 1, 0 );
rc-web@42 1007 }
rc-web@42 1008 }
rc-web@42 1009 function navigateUp() {
rc-web@42 1010 // Prioritize hiding fragments
rc-web@42 1011 if( overviewIsActive() || previousFragment() === false ) {
rc-web@42 1012 slide( indexh, indexv - 1 );
rc-web@42 1013 }
rc-web@42 1014 }
rc-web@42 1015 function navigateDown() {
rc-web@42 1016 // Prioritize revealing fragments
rc-web@42 1017 if( overviewIsActive() || nextFragment() === false ) {
rc-web@42 1018 slide( indexh, indexv + 1 );
rc-web@42 1019 }
rc-web@42 1020 }
rc-web@42 1021
rc-web@42 1022 /**
rc-web@42 1023 * Navigates backwards, prioritized in the following order:
rc-web@42 1024 * 1) Previous fragment
rc-web@42 1025 * 2) Previous vertical slide
rc-web@42 1026 * 3) Previous horizontal slide
rc-web@42 1027 */
rc-web@42 1028 function navigatePrev() {
rc-web@42 1029 // Prioritize revealing fragments
rc-web@42 1030 if( previousFragment() === false ) {
rc-web@42 1031 if( availableRoutes().up ) {
rc-web@42 1032 navigateUp();
rc-web@42 1033 }
rc-web@42 1034 else {
rc-web@42 1035 // Fetch the previous horizontal slide, if there is one
rc-web@42 1036 var previousSlide = document.querySelector( '.reveal .slides>section.past:nth-child(' + indexh + ')' );
rc-web@42 1037
rc-web@42 1038 if( previousSlide ) {
rc-web@42 1039 indexv = ( previousSlide.querySelectorAll('section').length + 1 ) || 0;
rc-web@42 1040 indexh --;
rc-web@42 1041 slide();
rc-web@42 1042 }
rc-web@42 1043 }
rc-web@42 1044 }
rc-web@42 1045 }
rc-web@42 1046
rc-web@42 1047 /**
rc-web@42 1048 * Same as #navigatePrev() but navigates forwards.
rc-web@42 1049 */
rc-web@42 1050 function navigateNext() {
rc-web@42 1051 // Prioritize revealing fragments
rc-web@42 1052 if( nextFragment() === false ) {
rc-web@42 1053 availableRoutes().down ? navigateDown() : navigateRight();
rc-web@42 1054 }
rc-web@42 1055
rc-web@42 1056 // If auto-sliding is enabled we need to cue up
rc-web@42 1057 // another timeout
rc-web@42 1058 cueAutoSlide();
rc-web@42 1059 }
rc-web@42 1060
rc-web@42 1061 /**
rc-web@42 1062 * Toggles the slide overview mode on and off.
rc-web@42 1063 */
rc-web@42 1064 function toggleOverview() {
rc-web@42 1065 if( overviewIsActive() ) {
rc-web@42 1066 deactivateOverview();
rc-web@42 1067 }
rc-web@42 1068 else {
rc-web@42 1069 activateOverview();
rc-web@42 1070 }
rc-web@42 1071 }
rc-web@42 1072
rc-web@42 1073 // Expose some methods publicly
rc-web@42 1074 return {
rc-web@42 1075 initialize: initialize,
rc-web@42 1076 navigateTo: navigateTo,
rc-web@42 1077 navigateLeft: navigateLeft,
rc-web@42 1078 navigateRight: navigateRight,
rc-web@42 1079 navigateUp: navigateUp,
rc-web@42 1080 navigateDown: navigateDown,
rc-web@42 1081 navigatePrev: navigatePrev,
rc-web@42 1082 navigateNext: navigateNext,
rc-web@42 1083 toggleOverview: toggleOverview,
rc-web@42 1084
rc-web@42 1085 // Adds or removes all internal event listeners (such as keyboard)
rc-web@42 1086 addEventListeners: addEventListeners,
rc-web@42 1087 removeEventListeners: removeEventListeners,
rc-web@42 1088
rc-web@42 1089 // Returns the indices of the current, or specified, slide
rc-web@42 1090 getIndices: function( slide ) {
rc-web@42 1091 // By default, return the current indices
rc-web@42 1092 var h = indexh,
rc-web@42 1093 v = indexv;
rc-web@42 1094
rc-web@42 1095 // If a slide is specified, return the indices of that slide
rc-web@42 1096 if( slide ) {
rc-web@42 1097 var isVertical = !!slide.parentNode.nodeName.match( /section/gi );
rc-web@42 1098 var slideh = isVertical ? slide.parentNode : slide;
rc-web@42 1099
rc-web@42 1100 // Select all horizontal slides
rc-web@42 1101 var horizontalSlides = Array.prototype.slice.call( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) );
rc-web@42 1102
rc-web@42 1103 // Now that we know which the horizontal slide is, get its index
rc-web@42 1104 h = Math.max( horizontalSlides.indexOf( slideh ), 0 );
rc-web@42 1105
rc-web@42 1106 // If this is a vertical slide, grab the vertical index
rc-web@42 1107 if( isVertical ) {
rc-web@42 1108 v = Math.max( Array.prototype.slice.call( slide.parentNode.children ).indexOf( slide ), 0 );
rc-web@42 1109 }
rc-web@42 1110 }
rc-web@42 1111
rc-web@42 1112 return { h: h, v: v };
rc-web@42 1113 },
rc-web@42 1114
rc-web@42 1115 // Returns the previous slide element, may be null
rc-web@42 1116 getPreviousSlide: function() {
rc-web@42 1117 return previousSlide
rc-web@42 1118 },
rc-web@42 1119
rc-web@42 1120 // Returns the current slide element
rc-web@42 1121 getCurrentSlide: function() {
rc-web@42 1122 return currentSlide
rc-web@42 1123 },
rc-web@42 1124
rc-web@42 1125 // Helper method, retrieves query string as a key/value hash
rc-web@42 1126 getQueryHash: function() {
rc-web@42 1127 var query = {};
rc-web@42 1128
rc-web@42 1129 location.search.replace( /[A-Z0-9]+?=(\w*)/gi, function(a) {
rc-web@42 1130 query[ a.split( '=' ).shift() ] = a.split( '=' ).pop();
rc-web@42 1131 } );
rc-web@42 1132
rc-web@42 1133 return query;
rc-web@42 1134 },
rc-web@42 1135
rc-web@42 1136 // Forward event binding to the reveal DOM element
rc-web@42 1137 addEventListener: function( type, listener, useCapture ) {
rc-web@42 1138 if( 'addEventListener' in window ) {
rc-web@42 1139 ( dom.wrapper || document.querySelector( '.reveal' ) ).addEventListener( type, listener, useCapture );
rc-web@42 1140 }
rc-web@42 1141 },
rc-web@42 1142 removeEventListener: function( type, listener, useCapture ) {
rc-web@42 1143 if( 'addEventListener' in window ) {
rc-web@42 1144 ( dom.wrapper || document.querySelector( '.reveal' ) ).removeEventListener( type, listener, useCapture );
rc-web@42 1145 }
rc-web@42 1146 }
rc-web@42 1147 };
rc-web@42 1148
rc-web@42 1149 })();