orgmode-cli-tools 0.1.0

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