slide-em-up 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/README.md +16 -23
  2. data/lib/slide-em-up.rb +1 -0
  3. data/lib/slide-em-up/markdown.rb +41 -0
  4. data/lib/slide-em-up/presentation.rb +14 -32
  5. data/lib/slide-em-up/remote_api.rb +2 -1
  6. data/lib/slide-em-up/version.rb +1 -1
  7. data/themes/CSSS/css/slideshow.css +69 -123
  8. data/themes/CSSS/css/theme.css +11 -36
  9. data/themes/CSSS/index.erb +1 -0
  10. data/themes/CSSS/js/prefixfree.min.js +13 -0
  11. data/themes/CSSS/js/slideshow.js +319 -234
  12. data/themes/common/css/pygments/manni.css +61 -0
  13. data/themes/common/fonts/Lato-BoldItalic.woff +0 -0
  14. data/themes/common/fonts/Lato-Italic.woff +0 -0
  15. data/themes/common/fonts/Lato-bold.woff +0 -0
  16. data/themes/common/fonts/Lato.woff +0 -0
  17. data/themes/common/fonts/OpenSans-Bold.woff +0 -0
  18. data/themes/common/fonts/OpenSans-BoldItalic.woff +0 -0
  19. data/themes/common/fonts/OpenSans-Italic.woff +0 -0
  20. data/themes/common/fonts/OpenSans.woff +0 -0
  21. data/themes/common/fonts/PTMono.woff +0 -0
  22. data/themes/common/fonts/PTSans.Bold.Italic.woff +0 -0
  23. data/themes/common/fonts/PTSans.Bold.woff +0 -0
  24. data/themes/common/fonts/PTSans.Italic.woff +0 -0
  25. data/themes/common/fonts/PTSans.Narrow.Bold.woff +0 -0
  26. data/themes/common/fonts/PTSans.Narrow.woff +0 -0
  27. data/themes/common/fonts/PTSans.woff +0 -0
  28. data/themes/io2012/README +2 -0
  29. data/themes/io2012/css/default.css +1481 -0
  30. data/themes/io2012/css/fonts.css +24 -0
  31. data/themes/io2012/css/phone.css +27 -0
  32. data/themes/io2012/images/google_developers_icon_128.png +0 -0
  33. data/themes/io2012/images/io2012_logo.png +0 -0
  34. data/themes/io2012/index.erb +73 -0
  35. data/themes/io2012/js/hammer.js +586 -0
  36. data/themes/io2012/js/modernizr.custom.45394.js +4 -0
  37. data/themes/io2012/js/order.js +8 -0
  38. data/themes/io2012/js/polyfills/classList.min.js +2 -0
  39. data/themes/io2012/js/polyfills/dataset.min.js +2 -0
  40. data/themes/io2012/js/polyfills/history.min.js +1 -0
  41. data/themes/io2012/js/prettify/lang-apollo.js +2 -0
  42. data/themes/io2012/js/prettify/lang-clj.js +18 -0
  43. data/themes/io2012/js/prettify/lang-css.js +2 -0
  44. data/themes/io2012/js/prettify/lang-go.js +1 -0
  45. data/themes/io2012/js/prettify/lang-hs.js +2 -0
  46. data/themes/io2012/js/prettify/lang-lisp.js +3 -0
  47. data/themes/io2012/js/prettify/lang-lua.js +2 -0
  48. data/themes/io2012/js/prettify/lang-ml.js +2 -0
  49. data/themes/io2012/js/prettify/lang-n.js +4 -0
  50. data/themes/io2012/js/prettify/lang-proto.js +1 -0
  51. data/themes/io2012/js/prettify/lang-scala.js +2 -0
  52. data/themes/io2012/js/prettify/lang-sql.js +2 -0
  53. data/themes/io2012/js/prettify/lang-tex.js +1 -0
  54. data/themes/io2012/js/prettify/lang-vb.js +2 -0
  55. data/themes/io2012/js/prettify/lang-vhdl.js +3 -0
  56. data/themes/io2012/js/prettify/lang-wiki.js +2 -0
  57. data/themes/io2012/js/prettify/lang-xq.js +3 -0
  58. data/themes/io2012/js/prettify/lang-yaml.js +2 -0
  59. data/themes/io2012/js/prettify/prettify.css +1 -0
  60. data/themes/io2012/js/prettify/prettify.js +28 -0
  61. data/themes/io2012/js/require-1.0.8.min.js +33 -0
  62. data/themes/io2012/js/slide-controller.js +109 -0
  63. data/themes/io2012/js/slide-deck.js +768 -0
  64. data/themes/io2012/js/slides.js +5 -0
  65. data/themes/memories/css/slideshow.css +191 -50
  66. data/themes/memories/css/theme.css +10 -4
  67. data/themes/memories/index.erb +2 -0
  68. data/themes/memories/js/prefixfree.min.js +13 -0
  69. data/themes/memories/js/slideshow.js +526 -371
  70. data/themes/reveal/README +2 -0
  71. data/themes/reveal/css/main.css +1029 -0
  72. data/themes/reveal/css/reset.css +57 -0
  73. data/themes/reveal/index.erb +102 -0
  74. data/themes/reveal/js/classList.js +2 -0
  75. data/themes/reveal/js/head.min.js +8 -0
  76. data/themes/reveal/js/reveal.js +951 -0
  77. data/themes/shower/css/fonts.css +39 -7
  78. data/themes/shower/css/reset.css +21 -21
  79. data/themes/shower/css/style.css +108 -75
  80. data/themes/shower/index.erb +3 -0
  81. data/themes/shower/js/script.js +160 -92
  82. metadata +80 -18
@@ -0,0 +1,57 @@
1
+ /* http://meyerweb.com/eric/tools/css/reset/
2
+ v2.0 | 20110126
3
+ License: none (public domain)
4
+ */
5
+
6
+ html, body, div, span, applet, object, iframe,
7
+ h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8
+ a, abbr, acronym, address, big, cite, code,
9
+ del, dfn, em, img, ins, kbd, q, s, samp,
10
+ small, strike, strong, sub, sup, tt, var,
11
+ b, u, i, center,
12
+ dl, dt, dd, ol, ul, li,
13
+ fieldset, form, label, legend,
14
+ table, caption, tbody, tfoot, thead, tr, th, td,
15
+ article, aside, canvas, details, embed,
16
+ figure, figcaption, footer, header, hgroup,
17
+ menu, nav, output, ruby, section, summary,
18
+ time, mark, audio, video {
19
+ margin: 0;
20
+ padding: 0;
21
+ border: 0;
22
+ font-size: 100%;
23
+ font: inherit;
24
+ vertical-align: baseline;
25
+ }
26
+ /* HTML5 display-role reset for older browsers */
27
+ article, aside, details, figcaption, figure,
28
+ footer, header, hgroup, menu, nav, section {
29
+ display: block;
30
+ }
31
+ body {
32
+ line-height: 1;
33
+ }
34
+ ol, ul {
35
+ list-style: none;
36
+ }
37
+ blockquote, q {
38
+ quotes: none;
39
+ }
40
+ blockquote:before, blockquote:after,
41
+ q:before, q:after {
42
+ content: '';
43
+ content: none;
44
+ }
45
+ table {
46
+ border-collapse: collapse;
47
+ border-spacing: 0;
48
+ }
49
+
50
+
51
+ /* HTML5BP:
52
+ These selection declarations have to be separate.
53
+ No text-shadow: twitter.com/miketaylr/status/12228805301
54
+ Also: hot pink. */
55
+ ::-moz-selection{ background: #FF5E99; color:#fff; text-shadow: none; }
56
+ ::selection { background:#FF5E99; color:#fff; text-shadow: none; }
57
+
@@ -0,0 +1,102 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="utf-8">
6
+
7
+ <title><%= meta.title %></title>
8
+ <meta name="author" content="<%= meta.author %>">
9
+
10
+ <meta name="apple-mobile-web-app-capable" content="yes" />
11
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
12
+
13
+ <% (theme.css + meta.css).each do |css| %>
14
+ <link rel="stylesheet" href="<%= css %>">
15
+ <% end %>
16
+ <link rel="stylesheet" href="css/pygments/colorful.css">
17
+ </head>
18
+
19
+ <body>
20
+
21
+ <div class="reveal">
22
+
23
+ <!-- Used to fade in a background when a specific slide state is reached -->
24
+ <div class="state-background"></div>
25
+
26
+ <!-- Any section element inside of this container is displayed as a slide -->
27
+ <div class="slides">
28
+ <% sections.each do |section| %>
29
+ <section>
30
+ <% section.slides.each do |slide| %>
31
+ <section class="<%= slide.classes %>">
32
+ <%= slide.html %>
33
+ </section>
34
+ <% end %>
35
+ </section>
36
+ <% end %>
37
+ </div>
38
+
39
+ <!-- The navigational controls UI -->
40
+ <aside class="controls">
41
+ <a class="left" href="#">&#x25C4;</a>
42
+ <a class="right" href="#">&#x25BA;</a>
43
+ <a class="up" href="#">&#x25B2;</a>
44
+ <a class="down" href="#">&#x25BC;</a>
45
+ </aside>
46
+
47
+ <!-- Displays presentation progress, max value changes via JS to reflect # of slides -->
48
+ <div class="progress"><span></span></div>
49
+
50
+ </div>
51
+
52
+ <!-- Optional libraries for code syntax highlighting and classList support in IE9 -->
53
+ <script src="js/head.min.js"></script>
54
+
55
+ <script>
56
+ // Load the main reveal.js script
57
+ head.js( 'js/reveal.js', function() {
58
+ // Parse the query string into a key/value object
59
+ var query = {};
60
+
61
+ location.search.replace( /[A-Z0-9]+?=(\w*)/gi, function(a) {
62
+ query[ a.split( '=' ).shift() ] = a.split( '=' ).pop();
63
+ } );
64
+
65
+ Reveal.initialize({
66
+ // Display controls in the bottom right corner
67
+ controls: true,
68
+
69
+ // Display a presentation progress bar
70
+ progress: true,
71
+
72
+ // If true; each slide will be pushed to the browser history
73
+ history: true,
74
+
75
+ // Loops the presentation, defaults to false
76
+ loop: false,
77
+
78
+ // Flags if mouse wheel navigation should be enabled
79
+ mouseWheel: true,
80
+
81
+ // Apply a 3D roll to links on hover
82
+ rollingLinks: true,
83
+
84
+ // UI style
85
+ theme: query.theme || 'default', // default/neon/beige
86
+
87
+ // Transition style
88
+ transition: query.transition || 'default' // default/cube/page/concave/linear(2d)
89
+ });
90
+ } );
91
+
92
+ // Load third party scripts
93
+ head.js( 'lib/js/classList.js' );
94
+
95
+ </script>
96
+
97
+ <% meta.js.each do |js| %>
98
+ <script src="<%= js %>"></script>
99
+ <% end %>
100
+
101
+ </body>
102
+ </html>
@@ -0,0 +1,2 @@
1
+ /*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
2
+ if(typeof document!=="undefined"&&!("classList" in document.createElement("a"))){(function(j){var a="classList",f="prototype",m=(j.HTMLElement||j.Element)[f],b=Object,k=String[f].trim||function(){return this.replace(/^\s+|\s+$/g,"")},c=Array[f].indexOf||function(q){var p=0,o=this.length;for(;p<o;p++){if(p in this&&this[p]===q){return p}}return -1},n=function(o,p){this.name=o;this.code=DOMException[o];this.message=p},g=function(p,o){if(o===""){throw new n("SYNTAX_ERR","An invalid or illegal string was specified")}if(/\s/.test(o)){throw new n("INVALID_CHARACTER_ERR","String contains an invalid character")}return c.call(p,o)},d=function(s){var r=k.call(s.className),q=r?r.split(/\s+/):[],p=0,o=q.length;for(;p<o;p++){this.push(q[p])}this._updateClassName=function(){s.className=this.toString()}},e=d[f]=[],i=function(){return new d(this)};n[f]=Error[f];e.item=function(o){return this[o]||null};e.contains=function(o){o+="";return g(this,o)!==-1};e.add=function(o){o+="";if(g(this,o)===-1){this.push(o);this._updateClassName()}};e.remove=function(p){p+="";var o=g(this,p);if(o!==-1){this.splice(o,1);this._updateClassName()}};e.toggle=function(o){o+="";if(g(this,o)===-1){this.add(o)}else{this.remove(o)}};e.toString=function(){return this.join(" ")};if(b.defineProperty){var l={get:i,enumerable:true,configurable:true};try{b.defineProperty(m,a,l)}catch(h){if(h.number===-2146823252){l.enumerable=false;b.defineProperty(m,a,l)}}}else{if(b[f].__defineGetter__){m.__defineGetter__(a,i)}}}(self))};
@@ -0,0 +1,8 @@
1
+ /**
2
+ Head JS The only script in your <HEAD>
3
+ Copyright Tero Piirainen (tipiirai)
4
+ License MIT / http://bit.ly/mit-license
5
+ Version 0.96
6
+
7
+ http://headjs.com
8
+ */(function(a){function z(){d||(d=!0,s(e,function(a){p(a)}))}function y(c,d){var e=a.createElement("script");e.type="text/"+(c.type||"javascript"),e.src=c.src||c,e.async=!1,e.onreadystatechange=e.onload=function(){var a=e.readyState;!d.done&&(!a||/loaded|complete/.test(a))&&(d.done=!0,d())},(a.body||b).appendChild(e)}function x(a,b){if(a.state==o)return b&&b();if(a.state==n)return k.ready(a.name,b);if(a.state==m)return a.onpreload.push(function(){x(a,b)});a.state=n,y(a.url,function(){a.state=o,b&&b(),s(g[a.name],function(a){p(a)}),u()&&d&&s(g.ALL,function(a){p(a)})})}function w(a,b){a.state===undefined&&(a.state=m,a.onpreload=[],y({src:a.url,type:"cache"},function(){v(a)}))}function v(a){a.state=l,s(a.onpreload,function(a){a.call()})}function u(a){a=a||h;var b;for(var c in a){if(a.hasOwnProperty(c)&&a[c].state!=o)return!1;b=!0}return b}function t(a){return Object.prototype.toString.call(a)=="[object Function]"}function s(a,b){if(!!a){typeof a=="object"&&(a=[].slice.call(a));for(var c=0;c<a.length;c++)b.call(a,a[c],c)}}function r(a){var b;if(typeof a=="object")for(var c in a)a[c]&&(b={name:c,url:a[c]});else b={name:q(a),url:a};var d=h[b.name];if(d&&d.url===b.url)return d;h[b.name]=b;return b}function q(a){var b=a.split("/"),c=b[b.length-1],d=c.indexOf("?");return d!=-1?c.substring(0,d):c}function p(a){a._done||(a(),a._done=1)}var b=a.documentElement,c,d,e=[],f=[],g={},h={},i=a.createElement("script").async===!0||"MozAppearance"in a.documentElement.style||window.opera,j=window.head_conf&&head_conf.head||"head",k=window[j]=window[j]||function(){k.ready.apply(null,arguments)},l=1,m=2,n=3,o=4;i?k.js=function(){var a=arguments,b=a[a.length-1],c={};t(b)||(b=null),s(a,function(d,e){d!=b&&(d=r(d),c[d.name]=d,x(d,b&&e==a.length-2?function(){u(c)&&p(b)}:null))});return k}:k.js=function(){var a=arguments,b=[].slice.call(a,1),d=b[0];if(!c){f.push(function(){k.js.apply(null,a)});return k}d?(s(b,function(a){t(a)||w(r(a))}),x(r(a[0]),t(d)?d:function(){k.js.apply(null,b)})):x(r(a[0]));return k},k.ready=function(b,c){if(b==a){d?p(c):e.push(c);return k}t(b)&&(c=b,b="ALL");if(typeof b!="string"||!t(c))return k;var f=h[b];if(f&&f.state==o||b=="ALL"&&u()&&d){p(c);return k}var i=g[b];i?i.push(c):i=g[b]=[c];return k},k.ready(a,function(){u()&&s(g.ALL,function(a){p(a)}),k.feature&&k.feature("domloaded",!0)});if(window.addEventListener)a.addEventListener("DOMContentLoaded",z,!1),window.addEventListener("load",z,!1);else if(window.attachEvent){a.attachEvent("onreadystatechange",function(){a.readyState==="complete"&&z()});var A=1;try{A=window.frameElement}catch(B){}!A&&b.doScroll&&function(){try{b.doScroll("left"),z()}catch(a){setTimeout(arguments.callee,1);return}}(),window.attachEvent("onload",z)}!a.readyState&&a.addEventListener&&(a.readyState="loading",a.addEventListener("DOMContentLoaded",handler=function(){a.removeEventListener("DOMContentLoaded",handler,!1),a.readyState="complete"},!1)),setTimeout(function(){c=!0,s(f,function(a){a()})},300)})(document)
@@ -0,0 +1,951 @@
1
+ /*!
2
+ * reveal.js 1.4
3
+ * http://lab.hakim.se/reveal-js
4
+ * MIT licensed
5
+ *
6
+ * Copyright (C) 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
+ // The horizontal and verical index of the currently active slide
16
+ indexh = 0,
17
+ indexv = 0,
18
+
19
+ // Configurations options, can be overridden at initialization time
20
+ config = {
21
+ controls: true,
22
+ progress: false,
23
+ history: false,
24
+ loop: false,
25
+ mouseWheel: true,
26
+ rollingLinks: true,
27
+ transition: 'default',
28
+ theme: 'default'
29
+ },
30
+
31
+ // Slides may hold a data-state attribute which we pick up and apply
32
+ // as a class to the body. This list contains the combined state of
33
+ // all current slides.
34
+ state = [],
35
+
36
+ // Cached references to DOM elements
37
+ dom = {},
38
+
39
+ // Detect support for CSS 3D transforms
40
+ supports3DTransforms = document.body.style['WebkitPerspective'] !== undefined ||
41
+ document.body.style['MozPerspective'] !== undefined ||
42
+ document.body.style['msPerspective'] !== undefined ||
43
+ document.body.style['OPerspective'] !== undefined ||
44
+ document.body.style['perspective'] !== undefined,
45
+
46
+ supports2DTransforms = document.body.style['WebkitTransform'] !== undefined ||
47
+ document.body.style['MozTransform'] !== undefined ||
48
+ document.body.style['msTransform'] !== undefined ||
49
+ document.body.style['OTransform'] !== undefined ||
50
+ document.body.style['transform'] !== undefined,
51
+
52
+ // Detect support for elem.classList
53
+ supportsClassList = !!document.body.classList;
54
+
55
+ // Throttles mouse wheel navigation
56
+ mouseWheelTimeout = 0,
57
+
58
+ // Delays updates to the URL due to a Chrome thumbnailer bug
59
+ writeURLTimeout = 0,
60
+
61
+ // Holds information about the currently ongoing touch input
62
+ touch = {
63
+ startX: 0,
64
+ startY: 0,
65
+ startSpan: 0,
66
+ startCount: 0,
67
+ handled: false,
68
+ threshold: 40
69
+ };
70
+
71
+
72
+ /**
73
+ * Starts up the slideshow by applying configuration
74
+ * options and binding various events.
75
+ */
76
+ function initialize( options ) {
77
+
78
+ if( ( !supports2DTransforms && !supports3DTransforms ) || !supportsClassList ) {
79
+ document.body.setAttribute( 'class', 'no-transforms' );
80
+
81
+ // If the browser doesn't support core features we won't be
82
+ // using JavaScript to control the presentation
83
+ return;
84
+ }
85
+
86
+ // Cache references to DOM elements
87
+ dom.wrapper = document.querySelector( '.reveal' );
88
+ dom.progress = document.querySelector( '.reveal .progress' );
89
+ dom.progressbar = document.querySelector( '.reveal .progress span' );
90
+
91
+ if ( config.controls ) {
92
+ dom.controls = document.querySelector( '.reveal .controls' );
93
+ dom.controlsLeft = document.querySelector( '.reveal .controls .left' );
94
+ dom.controlsRight = document.querySelector( '.reveal .controls .right' );
95
+ dom.controlsUp = document.querySelector( '.reveal .controls .up' );
96
+ dom.controlsDown = document.querySelector( '.reveal .controls .down' );
97
+ }
98
+
99
+ addEventListeners();
100
+
101
+ // Copy options over to our config object
102
+ extend( config, options );
103
+
104
+ // Updates the presentation to match the current configuration values
105
+ configure();
106
+
107
+ // Read the initial hash
108
+ readURL();
109
+
110
+ // Set up hiding of the browser address bar
111
+ if( navigator.userAgent.match( /(iphone|ipod|android)/i ) ) {
112
+ // Give the page some scrollable overflow
113
+ document.documentElement.style.overflow = 'scroll';
114
+ document.body.style.height = '120%';
115
+
116
+ // Events that should trigger the address bar to hide
117
+ window.addEventListener( 'load', removeAddressBar, false );
118
+ window.addEventListener( 'orientationchange', removeAddressBar, false );
119
+ }
120
+
121
+ }
122
+
123
+ function configure() {
124
+ // Fall back on the 2D transform theme 'linear'
125
+ if( supports3DTransforms === false ) {
126
+ config.transition = 'linear';
127
+ }
128
+
129
+ if( config.controls && dom.controls ) {
130
+ dom.controls.style.display = 'block';
131
+ }
132
+
133
+ if( config.progress ) {
134
+ dom.progress.style.display = 'block';
135
+ }
136
+
137
+ if( config.transition !== 'default' ) {
138
+ dom.wrapper.classList.add( config.transition );
139
+ }
140
+
141
+ if( config.theme !== 'default' ) {
142
+ document.documentElement.classList.add( 'theme-' + config.theme );
143
+ }
144
+
145
+ if( config.mouseWheel ) {
146
+ document.addEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF
147
+ document.addEventListener( 'mousewheel', onDocumentMouseScroll, false );
148
+ }
149
+
150
+ if( config.rollingLinks ) {
151
+ // Add some 3D magic to our anchors
152
+ linkify();
153
+ }
154
+ }
155
+
156
+ function addEventListeners() {
157
+ document.addEventListener( 'keydown', onDocumentKeyDown, false );
158
+ document.addEventListener( 'touchstart', onDocumentTouchStart, false );
159
+ document.addEventListener( 'touchmove', onDocumentTouchMove, false );
160
+ document.addEventListener( 'touchend', onDocumentTouchEnd, false );
161
+ window.addEventListener( 'hashchange', onWindowHashChange, false );
162
+
163
+ if ( config.controls && dom.controls ) {
164
+ dom.controlsLeft.addEventListener( 'click', preventAndForward( navigateLeft ), false );
165
+ dom.controlsRight.addEventListener( 'click', preventAndForward( navigateRight ), false );
166
+ dom.controlsUp.addEventListener( 'click', preventAndForward( navigateUp ), false );
167
+ dom.controlsDown.addEventListener( 'click', preventAndForward( navigateDown ), false );
168
+ }
169
+ }
170
+
171
+ function removeEventListeners() {
172
+ document.removeEventListener( 'keydown', onDocumentKeyDown, false );
173
+ document.removeEventListener( 'touchstart', onDocumentTouchStart, false );
174
+ document.removeEventListener( 'touchmove', onDocumentTouchMove, false );
175
+ document.removeEventListener( 'touchend', onDocumentTouchEnd, false );
176
+ window.removeEventListener( 'hashchange', onWindowHashChange, false );
177
+
178
+ if ( config.controls && dom.controls ) {
179
+ dom.controlsLeft.removeEventListener( 'click', preventAndForward( navigateLeft ), false );
180
+ dom.controlsRight.removeEventListener( 'click', preventAndForward( navigateRight ), false );
181
+ dom.controlsUp.removeEventListener( 'click', preventAndForward( navigateUp ), false );
182
+ dom.controlsDown.removeEventListener( 'click', preventAndForward( navigateDown ), false );
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Extend object a with the properties of object b.
188
+ * If there's a conflict, object b takes precedence.
189
+ */
190
+ function extend( a, b ) {
191
+ for( var i in b ) {
192
+ a[ i ] = b[ i ];
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Measures the distance in pixels between point a
198
+ * and point b.
199
+ *
200
+ * @param {Object} a point with x/y properties
201
+ * @param {Object} b point with x/y properties
202
+ */
203
+ function distanceBetween( a, b ) {
204
+ var dx = a.x - b.x,
205
+ dy = a.y - b.y;
206
+
207
+ return Math.sqrt( dx*dx + dy*dy );
208
+ }
209
+
210
+ /**
211
+ * Prevents an events defaults behavior calls the
212
+ * specified delegate.
213
+ *
214
+ * @param {Function} delegate The method to call
215
+ * after the wrapper has been executed
216
+ */
217
+ function preventAndForward( delegate ) {
218
+ return function( event ) {
219
+ event.preventDefault();
220
+ delegate.call();
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Causes the address bar to hide on mobile devices,
226
+ * more vertical space ftw.
227
+ */
228
+ function removeAddressBar() {
229
+ setTimeout( function() {
230
+ window.scrollTo( 0, 1 );
231
+ }, 0 );
232
+ }
233
+
234
+ /**
235
+ * Handler for the document level 'keydown' event.
236
+ *
237
+ * @param {Object} event
238
+ */
239
+ function onDocumentKeyDown( event ) {
240
+ // FFT: Use document.querySelector( ':focus' ) === null
241
+ // instead of checking contentEditable?
242
+
243
+ // Disregard the event if the target is editable or a
244
+ // modifier is present
245
+ if ( event.target.contentEditable != 'inherit' || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey ) return;
246
+
247
+ var triggered = false;
248
+
249
+ switch( event.keyCode ) {
250
+ // p, page up
251
+ case 80: case 33: navigatePrev(); triggered = true; break;
252
+ // n, page down
253
+ case 78: case 34: navigateNext(); triggered = true; break;
254
+ // h, left
255
+ case 72: case 37: navigateLeft(); triggered = true; break;
256
+ // l, right
257
+ case 76: case 39: navigateRight(); triggered = true; break;
258
+ // k, up
259
+ case 75: case 38: navigateUp(); triggered = true; break;
260
+ // j, down
261
+ case 74: case 40: navigateDown(); triggered = true; break;
262
+ // home
263
+ case 36: navigateTo( 0 ); triggered = true; break;
264
+ // end
265
+ case 35: navigateTo( Number.MAX_VALUE ); triggered = true; break;
266
+ // space
267
+ case 32: overviewIsActive() ? deactivateOverview() : navigateNext(); triggered = true; break;
268
+ // return
269
+ case 13: if( overviewIsActive() ) { deactivateOverview(); triggered = true; } break;
270
+ }
271
+
272
+ if( triggered ) {
273
+ event.preventDefault();
274
+ }
275
+ else if ( event.keyCode === 27 && supports3DTransforms ) {
276
+ if( overviewIsActive() ) {
277
+ deactivateOverview();
278
+ }
279
+ else {
280
+ activateOverview();
281
+ }
282
+
283
+ event.preventDefault();
284
+ }
285
+
286
+ }
287
+
288
+ /**
289
+ * Handler for the document level 'touchstart' event,
290
+ * enables support for swipe and pinch gestures.
291
+ */
292
+ function onDocumentTouchStart( event ) {
293
+ touch.startX = event.touches[0].clientX;
294
+ touch.startY = event.touches[0].clientY;
295
+ touch.startCount = event.touches.length;
296
+
297
+ // If there's two touches we need to memorize the distance
298
+ // between those two points to detect pinching
299
+ if( event.touches.length === 2 ) {
300
+ touch.startSpan = distanceBetween( {
301
+ x: event.touches[1].clientX,
302
+ y: event.touches[1].clientY
303
+ }, {
304
+ x: touch.startX,
305
+ y: touch.startY
306
+ } );
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Handler for the document level 'touchmove' event.
312
+ */
313
+ function onDocumentTouchMove( event ) {
314
+ // Each touch should only trigger one action
315
+ if( !touch.handled ) {
316
+ var currentX = event.touches[0].clientX;
317
+ var currentY = event.touches[0].clientY;
318
+
319
+ // If the touch started off with two points and still has
320
+ // two active touches; test for the pinch gesture
321
+ if( event.touches.length === 2 && touch.startCount === 2 ) {
322
+
323
+ // The current distance in pixels between the two touch points
324
+ var currentSpan = distanceBetween( {
325
+ x: event.touches[1].clientX,
326
+ y: event.touches[1].clientY
327
+ }, {
328
+ x: touch.startX,
329
+ y: touch.startY
330
+ } );
331
+
332
+ // If the span is larger than the desire amount we've got
333
+ // ourselves a pinch
334
+ if( Math.abs( touch.startSpan - currentSpan ) > touch.threshold ) {
335
+ touch.handled = true;
336
+
337
+ if( currentSpan < touch.startSpan ) {
338
+ activateOverview();
339
+ }
340
+ else {
341
+ deactivateOverview();
342
+ }
343
+ }
344
+
345
+ }
346
+ // There was only one touch point, look for a swipe
347
+ else if( event.touches.length === 1 ) {
348
+ var deltaX = currentX - touch.startX,
349
+ deltaY = currentY - touch.startY;
350
+
351
+ if( deltaX > touch.threshold && Math.abs( deltaX ) > Math.abs( deltaY ) ) {
352
+ touch.handled = true;
353
+ navigateLeft();
354
+ }
355
+ else if( deltaX < -touch.threshold && Math.abs( deltaX ) > Math.abs( deltaY ) ) {
356
+ touch.handled = true;
357
+ navigateRight();
358
+ }
359
+ else if( deltaY > touch.threshold ) {
360
+ touch.handled = true;
361
+ navigateUp();
362
+ }
363
+ else if( deltaY < -touch.threshold ) {
364
+ touch.handled = true;
365
+ navigateDown();
366
+ }
367
+ }
368
+
369
+ event.preventDefault();
370
+ }
371
+ }
372
+
373
+ /**
374
+ * Handler for the document level 'touchend' event.
375
+ */
376
+ function onDocumentTouchEnd( event ) {
377
+ touch.handled = false;
378
+ }
379
+
380
+ /**
381
+ * Handles mouse wheel scrolling, throttled to avoid
382
+ * skipping multiple slides.
383
+ */
384
+ function onDocumentMouseScroll( event ){
385
+ clearTimeout( mouseWheelTimeout );
386
+
387
+ mouseWheelTimeout = setTimeout( function() {
388
+ var delta = event.detail || -event.wheelDelta;
389
+ if( delta > 0 ) {
390
+ navigateNext();
391
+ }
392
+ else {
393
+ navigatePrev();
394
+ }
395
+ }, 100 );
396
+ }
397
+
398
+ /**
399
+ * Handler for the window level 'hashchange' event.
400
+ *
401
+ * @param {Object} event
402
+ */
403
+ function onWindowHashChange( event ) {
404
+ readURL();
405
+ }
406
+
407
+ /**
408
+ * Wrap all links in 3D goodness.
409
+ */
410
+ function linkify() {
411
+ if( supports3DTransforms ) {
412
+ var nodes = document.querySelectorAll( '.reveal .slides section a:not(.image)' );
413
+
414
+ for( var i = 0, len = nodes.length; i < len; i++ ) {
415
+ var node = nodes[i];
416
+
417
+ if( node.textContent && !node.querySelector( 'img' ) && ( !node.className || !node.classList.contains( node, 'roll' ) ) ) {
418
+ node.classList.add( 'roll' );
419
+ node.innerHTML = '<span data-title="'+ node.text +'">' + node.innerHTML + '</span>';
420
+ }
421
+ };
422
+ }
423
+ }
424
+
425
+ /**
426
+ * Displays the overview of slides (quick nav) by
427
+ * scaling down and arranging all slide elements.
428
+ *
429
+ * Experimental feature, might be dropped if perf
430
+ * can't be improved.
431
+ */
432
+ function activateOverview() {
433
+
434
+ dom.wrapper.classList.add( 'overview' );
435
+
436
+ var horizontalSlides = Array.prototype.slice.call( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ) );
437
+
438
+ for( var i = 0, len1 = horizontalSlides.length; i < len1; i++ ) {
439
+ var hslide = horizontalSlides[i],
440
+ htransform = 'translateZ(-2500px) translate(' + ( ( i - indexh ) * 105 ) + '%, 0%)';
441
+
442
+ hslide.setAttribute( 'data-index-h', i );
443
+ hslide.style.display = 'block';
444
+ hslide.style.WebkitTransform = htransform;
445
+ hslide.style.MozTransform = htransform;
446
+ hslide.style.msTransform = htransform;
447
+ hslide.style.OTransform = htransform;
448
+ hslide.style.transform = htransform;
449
+
450
+ if( !hslide.classList.contains( 'stack' ) ) {
451
+ // Navigate to this slide on click
452
+ hslide.addEventListener( 'click', onOverviewSlideClicked, true );
453
+ }
454
+
455
+ var verticalSlides = Array.prototype.slice.call( hslide.querySelectorAll( 'section' ) );
456
+
457
+ for( var j = 0, len2 = verticalSlides.length; j < len2; j++ ) {
458
+ var vslide = verticalSlides[j],
459
+ vtransform = 'translate(0%, ' + ( ( j - indexv ) * 105 ) + '%)';
460
+
461
+ vslide.setAttribute( 'data-index-h', i );
462
+ vslide.setAttribute( 'data-index-v', j );
463
+ vslide.style.display = 'block';
464
+ vslide.style.WebkitTransform = vtransform;
465
+ vslide.style.MozTransform = vtransform;
466
+ vslide.style.msTransform = vtransform;
467
+ vslide.style.OTransform = vtransform;
468
+ vslide.style.transform = vtransform;
469
+
470
+ // Navigate to this slide on click
471
+ vslide.addEventListener( 'click', onOverviewSlideClicked, true );
472
+ }
473
+
474
+ }
475
+ }
476
+
477
+ /**
478
+ * Exits the slide overview and enters the currently
479
+ * active slide.
480
+ */
481
+ function deactivateOverview() {
482
+ dom.wrapper.classList.remove( 'overview' );
483
+
484
+ var slides = Array.prototype.slice.call( document.querySelectorAll( '.reveal .slides section' ) );
485
+
486
+ for( var i = 0, len = slides.length; i < len; i++ ) {
487
+ var element = slides[i];
488
+
489
+ // Resets all transforms to use the external styles
490
+ element.style.WebkitTransform = '';
491
+ element.style.MozTransform = '';
492
+ element.style.msTransform = '';
493
+ element.style.OTransform = '';
494
+ element.style.transform = '';
495
+
496
+ element.removeEventListener( 'click', onOverviewSlideClicked );
497
+ }
498
+
499
+ slide();
500
+ }
501
+
502
+ /**
503
+ * Checks if the overview is currently active.
504
+ *
505
+ * @return {Boolean} true if the overview is active,
506
+ * false otherwise
507
+ */
508
+ function overviewIsActive() {
509
+ return dom.wrapper.classList.contains( 'overview' );
510
+ }
511
+
512
+ /**
513
+ * Invoked when a slide is and we're in the overview.
514
+ */
515
+ function onOverviewSlideClicked( event ) {
516
+ // TODO There's a bug here where the event listeners are not
517
+ // removed after deactivating the overview.
518
+ if( overviewIsActive() ) {
519
+ event.preventDefault();
520
+
521
+ deactivateOverview();
522
+
523
+ indexh = this.getAttribute( 'data-index-h' );
524
+ indexv = this.getAttribute( 'data-index-v' );
525
+
526
+ slide();
527
+ }
528
+ }
529
+
530
+ /**
531
+ * Updates one dimension of slides by showing the slide
532
+ * with the specified index.
533
+ *
534
+ * @param {String} selector A CSS selector that will fetch
535
+ * the group of slides we are working with
536
+ * @param {Number} index The index of the slide that should be
537
+ * shown
538
+ *
539
+ * @return {Number} The index of the slide that is now shown,
540
+ * might differ from the passed in index if it was out of
541
+ * bounds.
542
+ */
543
+ function updateSlides( selector, index ) {
544
+
545
+ // Select all slides and convert the NodeList result to
546
+ // an array
547
+ var slides = Array.prototype.slice.call( document.querySelectorAll( selector ) ),
548
+ slidesLength = slides.length;
549
+
550
+ if( slidesLength ) {
551
+
552
+ // Should the index loop?
553
+ if( config.loop ) {
554
+ index %= slidesLength;
555
+
556
+ if( index < 0 ) {
557
+ index = slidesLength + index;
558
+ }
559
+ }
560
+
561
+ // Enforce max and minimum index bounds
562
+ index = Math.max( Math.min( index, slidesLength - 1 ), 0 );
563
+
564
+ for( var i = 0; i < slidesLength; i++ ) {
565
+ var slide = slides[i];
566
+
567
+ // Optimization; hide all slides that are three or more steps
568
+ // away from the present slide
569
+ if( overviewIsActive() === false ) {
570
+ // The distance loops so that it measures 1 between the first
571
+ // and last slides
572
+ var distance = Math.abs( ( index - i ) % ( slidesLength - 3 ) ) || 0;
573
+
574
+ slide.style.display = distance > 3 ? 'none' : 'block';
575
+ }
576
+
577
+ slides[i].classList.remove( 'past' );
578
+ slides[i].classList.remove( 'present' );
579
+ slides[i].classList.remove( 'future' );
580
+
581
+ if( i < index ) {
582
+ // Any element previous to index is given the 'past' class
583
+ slides[i].classList.add( 'past' );
584
+ }
585
+ else if( i > index ) {
586
+ // Any element subsequent to index is given the 'future' class
587
+ slides[i].classList.add( 'future' );
588
+ }
589
+
590
+ // If this element contains vertical slides
591
+ if( slide.querySelector( 'section' ) ) {
592
+ slides[i].classList.add( 'stack' );
593
+ }
594
+ }
595
+
596
+ // Mark the current slide as present
597
+ slides[index].classList.add( 'present' );
598
+
599
+ // If this slide has a state associated with it, add it
600
+ // onto the current state of the deck
601
+ var slideState = slides[index].getAttribute( 'data-state' );
602
+ if( slideState ) {
603
+ state = state.concat( slideState.split( ' ' ) );
604
+ }
605
+ }
606
+ else {
607
+ // Since there are no slides we can't be anywhere beyond the
608
+ // zeroth index
609
+ index = 0;
610
+ }
611
+
612
+ return index;
613
+
614
+ }
615
+
616
+ /**
617
+ * Updates the visual slides to represent the currently
618
+ * set indices.
619
+ */
620
+ function slide( h, v ) {
621
+ // Remember the state before this slide
622
+ var stateBefore = state.concat();
623
+
624
+ // Reset the state array
625
+ state.length = 0;
626
+
627
+ var indexhBefore = indexh,
628
+ indexvBefore = indexv;
629
+
630
+ // Activate and transition to the new slide
631
+ indexh = updateSlides( HORIZONTAL_SLIDES_SELECTOR, h === undefined ? indexh : h );
632
+ indexv = updateSlides( VERTICAL_SLIDES_SELECTOR, v === undefined ? indexv : v );
633
+
634
+ // Apply the new state
635
+ stateLoop: for( var i = 0, len = state.length; i < len; i++ ) {
636
+ // Check if this state existed on the previous slide. If it
637
+ // did, we will avoid adding it repeatedly.
638
+ for( var j = 0; j < stateBefore.length; j++ ) {
639
+ if( stateBefore[j] === state[i] ) {
640
+ stateBefore.splice( j, 1 );
641
+ continue stateLoop;
642
+ }
643
+ }
644
+
645
+ document.documentElement.classList.add( state[i] );
646
+
647
+ // Dispatch custom event matching the state's name
648
+ dispatchEvent( state[i] );
649
+ }
650
+
651
+ // Clean up the remaints of the previous state
652
+ while( stateBefore.length ) {
653
+ document.documentElement.classList.remove( stateBefore.pop() );
654
+ }
655
+
656
+ // Update progress if enabled
657
+ if( config.progress ) {
658
+ dom.progressbar.style.width = ( indexh / ( document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ).length - 1 ) ) * window.innerWidth + 'px';
659
+ }
660
+
661
+ // Close the overview if it's active
662
+ if( overviewIsActive() ) {
663
+ activateOverview();
664
+ }
665
+
666
+ updateControls();
667
+
668
+ clearTimeout( writeURLTimeout );
669
+ writeURLTimeout = setTimeout( writeURL, 1500 );
670
+
671
+ // Only fire if the slide index is different from before
672
+ if( indexh !== indexhBefore || indexv !== indexvBefore ) {
673
+ // Query all horizontal slides in the deck
674
+ var horizontalSlides = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR );
675
+
676
+ // Find the previous and current horizontal slides
677
+ var previousHorizontalSlide = horizontalSlides[ indexhBefore ],
678
+ currentHorizontalSlide = horizontalSlides[ indexh ];
679
+
680
+ // Query all vertical slides inside of the previous and current horizontal slides
681
+ var previousVerticalSlides = previousHorizontalSlide.querySelectorAll( 'section' );
682
+ currentVerticalSlides = currentHorizontalSlide.querySelectorAll( 'section' );
683
+
684
+ // Dispatch an event notifying observers of the change in slide
685
+ dispatchEvent( 'slidechanged', {
686
+ // Include the current indices in the event
687
+ 'indexh': indexh,
688
+ 'indexv': indexv,
689
+
690
+ // Passes direct references to the slide HTML elements, attempts to find
691
+ // a vertical slide and falls back on the horizontal parent
692
+ 'previousSlide': previousVerticalSlides[ indexvBefore ] || previousHorizontalSlide,
693
+ 'currentSlide': currentVerticalSlides[ indexv ] || currentHorizontalSlide
694
+ } );
695
+ }
696
+ }
697
+
698
+ /**
699
+ * Updates the state and link pointers of the controls.
700
+ */
701
+ function updateControls() {
702
+ if ( !config.controls || !dom.controls ) {
703
+ return;
704
+ }
705
+
706
+ var routes = availableRoutes();
707
+
708
+ // Remove the 'enabled' class from all directions
709
+ [ dom.controlsLeft, dom.controlsRight, dom.controlsUp, dom.controlsDown ].forEach( function( node ) {
710
+ node.classList.remove( 'enabled' );
711
+ } )
712
+
713
+ if( routes.left ) dom.controlsLeft.classList.add( 'enabled' );
714
+ if( routes.right ) dom.controlsRight.classList.add( 'enabled' );
715
+ if( routes.up ) dom.controlsUp.classList.add( 'enabled' );
716
+ if( routes.down ) dom.controlsDown.classList.add( 'enabled' );
717
+ }
718
+
719
+ /**
720
+ * Determine what available routes there are for navigation.
721
+ *
722
+ * @return {Object} containing four booleans: left/right/up/down
723
+ */
724
+ function availableRoutes() {
725
+ var horizontalSlides = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR );
726
+ var verticalSlides = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR );
727
+
728
+ return {
729
+ left: indexh > 0,
730
+ right: indexh < horizontalSlides.length - 1,
731
+ up: indexv > 0,
732
+ down: indexv < verticalSlides.length - 1
733
+ };
734
+ }
735
+
736
+ /**
737
+ * Reads the current URL (hash) and navigates accordingly.
738
+ */
739
+ function readURL() {
740
+ // Break the hash down to separate components
741
+ var bits = window.location.hash.slice(2).split('/');
742
+
743
+ // Read the index components of the hash
744
+ indexh = parseInt( bits[0] ) || 0 ;
745
+ indexv = parseInt( bits[1] ) || 0 ;
746
+
747
+ navigateTo( indexh, indexv );
748
+ }
749
+
750
+ /**
751
+ * Updates the page URL (hash) to reflect the current
752
+ * state.
753
+ */
754
+ function writeURL() {
755
+ if( config.history ) {
756
+ var url = '/';
757
+
758
+ // Only include the minimum possible number of components in
759
+ // the URL
760
+ if( indexh > 0 || indexv > 0 ) url += indexh;
761
+ if( indexv > 0 ) url += '/' + indexv;
762
+
763
+ window.location.hash = url;
764
+ }
765
+ }
766
+
767
+ /**
768
+ * Dispatches an event of the specified type from the
769
+ * reveal DOM element.
770
+ */
771
+ function dispatchEvent( type, properties ) {
772
+ var event = document.createEvent( "HTMLEvents", 1, 2 );
773
+ event.initEvent( type, true, true );
774
+ extend( event, properties );
775
+ dom.wrapper.dispatchEvent( event );
776
+ }
777
+
778
+ /**
779
+ * Navigate to the next slide fragment.
780
+ *
781
+ * @return {Boolean} true if there was a next fragment,
782
+ * false otherwise
783
+ */
784
+ function nextFragment() {
785
+ // Vertical slides:
786
+ if( document.querySelector( VERTICAL_SLIDES_SELECTOR + '.present' ) ) {
787
+ var verticalFragments = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR + '.present .fragment:not(.visible)' );
788
+ if( verticalFragments.length ) {
789
+ verticalFragments[0].classList.add( 'visible' );
790
+
791
+ // Notify subscribers of the change
792
+ dispatchEvent( 'fragmentshown', { fragment: verticalFragments[0] } );
793
+ return true;
794
+ }
795
+ }
796
+ // Horizontal slides:
797
+ else {
798
+ var horizontalFragments = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.present .fragment:not(.visible)' );
799
+ if( horizontalFragments.length ) {
800
+ horizontalFragments[0].classList.add( 'visible' );
801
+
802
+ // Notify subscribers of the change
803
+ dispatchEvent( 'fragmentshown', { fragment: horizontalFragments[0] } );
804
+ return true;
805
+ }
806
+ }
807
+
808
+ return false;
809
+ }
810
+
811
+ /**
812
+ * Navigate to the previous slide fragment.
813
+ *
814
+ * @return {Boolean} true if there was a previous fragment,
815
+ * false otherwise
816
+ */
817
+ function previousFragment() {
818
+ // Vertical slides:
819
+ if( document.querySelector( VERTICAL_SLIDES_SELECTOR + '.present' ) ) {
820
+ var verticalFragments = document.querySelectorAll( VERTICAL_SLIDES_SELECTOR + '.present .fragment.visible' );
821
+ if( verticalFragments.length ) {
822
+ verticalFragments[ verticalFragments.length - 1 ].classList.remove( 'visible' );
823
+
824
+ // Notify subscribers of the change
825
+ dispatchEvent( 'fragmenthidden', { fragment: verticalFragments[ verticalFragments.length - 1 ] } );
826
+ return true;
827
+ }
828
+ }
829
+ // Horizontal slides:
830
+ else {
831
+ var horizontalFragments = document.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR + '.present .fragment.visible' );
832
+ if( horizontalFragments.length ) {
833
+ horizontalFragments[ horizontalFragments.length - 1 ].classList.remove( 'visible' );
834
+
835
+ // Notify subscribers of the change
836
+ dispatchEvent( 'fragmenthidden', { fragment: horizontalFragments[ horizontalFragments.length - 1 ] } );
837
+ return true;
838
+ }
839
+ }
840
+
841
+ return false;
842
+ }
843
+
844
+ /**
845
+ * Triggers a navigation to the specified indices.
846
+ *
847
+ * @param {Number} h The horizontal index of the slide to show
848
+ * @param {Number} v The vertical index of the slide to show
849
+ */
850
+ function navigateTo( h, v ) {
851
+ slide( h, v );
852
+ }
853
+
854
+ function navigateLeft() {
855
+ // Prioritize hiding fragments
856
+ if( overviewIsActive() || previousFragment() === false ) {
857
+ slide( indexh - 1, 0 );
858
+ }
859
+ }
860
+ function navigateRight() {
861
+ // Prioritize revealing fragments
862
+ if( overviewIsActive() || nextFragment() === false ) {
863
+ slide( indexh + 1, 0 );
864
+ }
865
+ }
866
+ function navigateUp() {
867
+ // Prioritize hiding fragments
868
+ if( overviewIsActive() || previousFragment() === false ) {
869
+ slide( indexh, indexv - 1 );
870
+ }
871
+ }
872
+ function navigateDown() {
873
+ // Prioritize revealing fragments
874
+ if( overviewIsActive() || nextFragment() === false ) {
875
+ slide( indexh, indexv + 1 );
876
+ }
877
+ }
878
+
879
+ /**
880
+ * Navigates backwards, prioritized in the following order:
881
+ * 1) Previous fragment
882
+ * 2) Previous vertical slide
883
+ * 3) Previous horizontal slide
884
+ */
885
+ function navigatePrev() {
886
+ // Prioritize revealing fragments
887
+ if( previousFragment() === false ) {
888
+ if( availableRoutes().up ) {
889
+ navigateUp();
890
+ }
891
+ else {
892
+ // Fetch the previous horizontal slide, if there is one
893
+ var previousSlide = document.querySelector( '.reveal .slides>section.past:nth-child(' + indexh + ')' );
894
+
895
+ if( previousSlide ) {
896
+ indexv = ( previousSlide.querySelectorAll('section').length + 1 ) || 0;
897
+ indexh --;
898
+ slide();
899
+ }
900
+ }
901
+ }
902
+ }
903
+
904
+ /**
905
+ * Same as #navigatePrev() but navigates forwards.
906
+ */
907
+ function navigateNext() {
908
+ // Prioritize revealing fragments
909
+ if( nextFragment() === false ) {
910
+ availableRoutes().down ? navigateDown() : navigateRight();
911
+ }
912
+ }
913
+
914
+ /**
915
+ * Toggles the slide overview mode on and off.
916
+ */
917
+ function toggleOverview() {
918
+ if( overviewIsActive() ) {
919
+ deactivateOverview();
920
+ }
921
+ else {
922
+ activateOverview();
923
+ }
924
+ }
925
+
926
+ // Expose some methods publicly
927
+ return {
928
+ initialize: initialize,
929
+ navigateTo: navigateTo,
930
+ navigateLeft: navigateLeft,
931
+ navigateRight: navigateRight,
932
+ navigateUp: navigateUp,
933
+ navigateDown: navigateDown,
934
+ navigatePrev: navigatePrev,
935
+ navigateNext: navigateNext,
936
+ toggleOverview: toggleOverview,
937
+
938
+ addEventListeners: addEventListeners,
939
+ removeEventListeners: removeEventListeners,
940
+
941
+ // Forward event binding to the reveal DOM element
942
+ addEventListener: function( type, listener, useCapture ) {
943
+ ( dom.wrapper || document.querySelector( '.reveal' ) ).addEventListener( type, listener, useCapture );
944
+ },
945
+ removeEventListener: function( type, listener, useCapture ) {
946
+ ( dom.wrapper || document.querySelector( '.reveal' ) ).removeEventListener( type, listener, useCapture );
947
+ }
948
+ };
949
+
950
+ })();
951
+