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.
- data/README.md +16 -23
- data/lib/slide-em-up.rb +1 -0
- data/lib/slide-em-up/markdown.rb +41 -0
- data/lib/slide-em-up/presentation.rb +14 -32
- data/lib/slide-em-up/remote_api.rb +2 -1
- data/lib/slide-em-up/version.rb +1 -1
- data/themes/CSSS/css/slideshow.css +69 -123
- data/themes/CSSS/css/theme.css +11 -36
- data/themes/CSSS/index.erb +1 -0
- data/themes/CSSS/js/prefixfree.min.js +13 -0
- data/themes/CSSS/js/slideshow.js +319 -234
- data/themes/common/css/pygments/manni.css +61 -0
- data/themes/common/fonts/Lato-BoldItalic.woff +0 -0
- data/themes/common/fonts/Lato-Italic.woff +0 -0
- data/themes/common/fonts/Lato-bold.woff +0 -0
- data/themes/common/fonts/Lato.woff +0 -0
- data/themes/common/fonts/OpenSans-Bold.woff +0 -0
- data/themes/common/fonts/OpenSans-BoldItalic.woff +0 -0
- data/themes/common/fonts/OpenSans-Italic.woff +0 -0
- data/themes/common/fonts/OpenSans.woff +0 -0
- data/themes/common/fonts/PTMono.woff +0 -0
- data/themes/common/fonts/PTSans.Bold.Italic.woff +0 -0
- data/themes/common/fonts/PTSans.Bold.woff +0 -0
- data/themes/common/fonts/PTSans.Italic.woff +0 -0
- data/themes/common/fonts/PTSans.Narrow.Bold.woff +0 -0
- data/themes/common/fonts/PTSans.Narrow.woff +0 -0
- data/themes/common/fonts/PTSans.woff +0 -0
- data/themes/io2012/README +2 -0
- data/themes/io2012/css/default.css +1481 -0
- data/themes/io2012/css/fonts.css +24 -0
- data/themes/io2012/css/phone.css +27 -0
- data/themes/io2012/images/google_developers_icon_128.png +0 -0
- data/themes/io2012/images/io2012_logo.png +0 -0
- data/themes/io2012/index.erb +73 -0
- data/themes/io2012/js/hammer.js +586 -0
- data/themes/io2012/js/modernizr.custom.45394.js +4 -0
- data/themes/io2012/js/order.js +8 -0
- data/themes/io2012/js/polyfills/classList.min.js +2 -0
- data/themes/io2012/js/polyfills/dataset.min.js +2 -0
- data/themes/io2012/js/polyfills/history.min.js +1 -0
- data/themes/io2012/js/prettify/lang-apollo.js +2 -0
- data/themes/io2012/js/prettify/lang-clj.js +18 -0
- data/themes/io2012/js/prettify/lang-css.js +2 -0
- data/themes/io2012/js/prettify/lang-go.js +1 -0
- data/themes/io2012/js/prettify/lang-hs.js +2 -0
- data/themes/io2012/js/prettify/lang-lisp.js +3 -0
- data/themes/io2012/js/prettify/lang-lua.js +2 -0
- data/themes/io2012/js/prettify/lang-ml.js +2 -0
- data/themes/io2012/js/prettify/lang-n.js +4 -0
- data/themes/io2012/js/prettify/lang-proto.js +1 -0
- data/themes/io2012/js/prettify/lang-scala.js +2 -0
- data/themes/io2012/js/prettify/lang-sql.js +2 -0
- data/themes/io2012/js/prettify/lang-tex.js +1 -0
- data/themes/io2012/js/prettify/lang-vb.js +2 -0
- data/themes/io2012/js/prettify/lang-vhdl.js +3 -0
- data/themes/io2012/js/prettify/lang-wiki.js +2 -0
- data/themes/io2012/js/prettify/lang-xq.js +3 -0
- data/themes/io2012/js/prettify/lang-yaml.js +2 -0
- data/themes/io2012/js/prettify/prettify.css +1 -0
- data/themes/io2012/js/prettify/prettify.js +28 -0
- data/themes/io2012/js/require-1.0.8.min.js +33 -0
- data/themes/io2012/js/slide-controller.js +109 -0
- data/themes/io2012/js/slide-deck.js +768 -0
- data/themes/io2012/js/slides.js +5 -0
- data/themes/memories/css/slideshow.css +191 -50
- data/themes/memories/css/theme.css +10 -4
- data/themes/memories/index.erb +2 -0
- data/themes/memories/js/prefixfree.min.js +13 -0
- data/themes/memories/js/slideshow.js +526 -371
- data/themes/reveal/README +2 -0
- data/themes/reveal/css/main.css +1029 -0
- data/themes/reveal/css/reset.css +57 -0
- data/themes/reveal/index.erb +102 -0
- data/themes/reveal/js/classList.js +2 -0
- data/themes/reveal/js/head.min.js +8 -0
- data/themes/reveal/js/reveal.js +951 -0
- data/themes/shower/css/fonts.css +39 -7
- data/themes/shower/css/reset.css +21 -21
- data/themes/shower/css/style.css +108 -75
- data/themes/shower/index.erb +3 -0
- data/themes/shower/js/script.js +160 -92
- 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="#">◄</a>
|
42
|
+
<a class="right" href="#">►</a>
|
43
|
+
<a class="up" href="#">▲</a>
|
44
|
+
<a class="down" href="#">▼</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
|
+
|