reveal-ck 3.8.1 → 3.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/files/reveal.js/Gruntfile.js +41 -40
- data/files/reveal.js/LICENSE +1 -1
- data/files/reveal.js/README.md +189 -107
- data/files/reveal.js/bower.json +2 -2
- data/files/reveal.js/css/print/pdf.css +10 -18
- data/files/reveal.js/css/reveal.css +344 -140
- data/files/reveal.js/css/reveal.scss +371 -76
- data/files/reveal.js/css/theme/README.md +2 -2
- data/files/reveal.js/css/theme/beige.css +19 -38
- data/files/reveal.js/css/theme/black.css +19 -38
- data/files/reveal.js/css/theme/blood.css +19 -38
- data/files/reveal.js/css/theme/league.css +19 -38
- data/files/reveal.js/css/theme/moon.css +19 -38
- data/files/reveal.js/css/theme/night.css +19 -38
- data/files/reveal.js/css/theme/serif.css +19 -38
- data/files/reveal.js/css/theme/simple.css +19 -38
- data/files/reveal.js/css/theme/sky.css +19 -38
- data/files/reveal.js/css/theme/solarized.css +19 -38
- data/files/reveal.js/css/theme/template/theme.scss +18 -45
- data/files/reveal.js/css/theme/white.css +19 -38
- data/files/reveal.js/demo.html +13 -7
- data/files/reveal.js/js/reveal.js +707 -242
- data/files/reveal.js/lib/js/head.min.js +1 -4
- data/files/reveal.js/package.json +16 -17
- data/files/reveal.js/plugin/highlight/highlight.js +3 -4
- data/files/reveal.js/plugin/markdown/example.html +7 -0
- data/files/reveal.js/plugin/markdown/example.md +5 -0
- data/files/reveal.js/plugin/markdown/markdown.js +1 -1
- data/files/reveal.js/plugin/math/math.js +4 -4
- data/files/reveal.js/plugin/multiplex/master.js +4 -1
- data/files/reveal.js/plugin/multiplex/package.json +1 -1
- data/files/reveal.js/plugin/notes/notes.html +48 -2
- data/files/reveal.js/plugin/notes/notes.js +9 -17
- data/files/reveal.js/plugin/print-pdf/print-pdf.js +9 -11
- data/files/reveal.js/plugin/search/search.js +127 -117
- data/files/reveal.js/plugin/zoom-js/zoom.js +16 -32
- data/files/reveal.js/test/qunit-2.5.0.css +436 -0
- data/files/reveal.js/test/qunit-2.5.0.js +5188 -0
- data/files/reveal.js/test/test-markdown-element-attributes.html +2 -2
- data/files/reveal.js/test/test-markdown-element-attributes.js +21 -23
- data/files/reveal.js/test/test-markdown-external.html +3 -3
- data/files/reveal.js/test/test-markdown-external.js +7 -11
- data/files/reveal.js/test/test-markdown-options.html +2 -2
- data/files/reveal.js/test/test-markdown-options.js +7 -6
- data/files/reveal.js/test/test-markdown-slide-attributes.html +2 -2
- data/files/reveal.js/test/test-markdown-slide-attributes.js +23 -26
- data/files/reveal.js/test/test-markdown.html +2 -2
- data/files/reveal.js/test/test-markdown.js +2 -6
- data/files/reveal.js/test/test-pdf.html +2 -2
- data/files/reveal.js/test/test-pdf.js +2 -5
- data/files/reveal.js/test/test.html +2 -2
- data/files/reveal.js/test/test.js +184 -188
- data/lib/reveal-ck/version.rb +1 -1
- metadata +4 -4
- data/files/reveal.js/test/qunit-1.12.0.css +0 -244
- data/files/reveal.js/test/qunit-1.12.0.js +0 -2212
@@ -28,8 +28,8 @@ body {
|
|
28
28
|
text-shadow: none;
|
29
29
|
}
|
30
30
|
|
31
|
-
.reveal .slides
|
32
|
-
.reveal .slides
|
31
|
+
.reveal .slides section,
|
32
|
+
.reveal .slides section>section {
|
33
33
|
line-height: 1.3;
|
34
34
|
font-weight: inherit;
|
35
35
|
}
|
@@ -134,11 +134,6 @@ body {
|
|
134
134
|
margin-left: 40px;
|
135
135
|
}
|
136
136
|
|
137
|
-
.reveal q,
|
138
|
-
.reveal blockquote {
|
139
|
-
quotes: none;
|
140
|
-
}
|
141
|
-
|
142
137
|
.reveal blockquote {
|
143
138
|
display: block;
|
144
139
|
position: relative;
|
@@ -174,8 +169,10 @@ body {
|
|
174
169
|
|
175
170
|
box-shadow: 0px 0px 6px rgba(0,0,0,0.3);
|
176
171
|
}
|
172
|
+
|
177
173
|
.reveal code {
|
178
174
|
font-family: monospace;
|
175
|
+
text-transform: none;
|
179
176
|
}
|
180
177
|
|
181
178
|
.reveal pre code {
|
@@ -220,9 +217,11 @@ body {
|
|
220
217
|
|
221
218
|
.reveal sup {
|
222
219
|
vertical-align: super;
|
220
|
+
font-size: smaller;
|
223
221
|
}
|
224
222
|
.reveal sub {
|
225
223
|
vertical-align: sub;
|
224
|
+
font-size: smaller;
|
226
225
|
}
|
227
226
|
|
228
227
|
.reveal small {
|
@@ -297,40 +296,8 @@ body {
|
|
297
296
|
* NAVIGATION CONTROLS
|
298
297
|
*********************************************/
|
299
298
|
|
300
|
-
.reveal .controls
|
301
|
-
|
302
|
-
border-right-color: $linkColor;
|
303
|
-
}
|
304
|
-
|
305
|
-
.reveal .controls .navigate-right,
|
306
|
-
.reveal .controls .navigate-right.enabled {
|
307
|
-
border-left-color: $linkColor;
|
308
|
-
}
|
309
|
-
|
310
|
-
.reveal .controls .navigate-up,
|
311
|
-
.reveal .controls .navigate-up.enabled {
|
312
|
-
border-bottom-color: $linkColor;
|
313
|
-
}
|
314
|
-
|
315
|
-
.reveal .controls .navigate-down,
|
316
|
-
.reveal .controls .navigate-down.enabled {
|
317
|
-
border-top-color: $linkColor;
|
318
|
-
}
|
319
|
-
|
320
|
-
.reveal .controls .navigate-left.enabled:hover {
|
321
|
-
border-right-color: $linkColorHover;
|
322
|
-
}
|
323
|
-
|
324
|
-
.reveal .controls .navigate-right.enabled:hover {
|
325
|
-
border-left-color: $linkColorHover;
|
326
|
-
}
|
327
|
-
|
328
|
-
.reveal .controls .navigate-up.enabled:hover {
|
329
|
-
border-bottom-color: $linkColorHover;
|
330
|
-
}
|
331
|
-
|
332
|
-
.reveal .controls .navigate-down.enabled:hover {
|
333
|
-
border-top-color: $linkColorHover;
|
299
|
+
.reveal .controls {
|
300
|
+
color: $linkColor;
|
334
301
|
}
|
335
302
|
|
336
303
|
|
@@ -340,13 +307,19 @@ body {
|
|
340
307
|
|
341
308
|
.reveal .progress {
|
342
309
|
background: rgba(0,0,0,0.2);
|
310
|
+
color: $linkColor;
|
343
311
|
}
|
344
312
|
.reveal .progress span {
|
345
|
-
background: $linkColor;
|
346
|
-
|
347
313
|
-webkit-transition: width 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985);
|
348
314
|
-moz-transition: width 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985);
|
349
|
-
|
315
|
+
transition: width 800ms cubic-bezier(0.260, 0.860, 0.440, 0.985);
|
350
316
|
}
|
351
317
|
|
352
|
-
|
318
|
+
/*********************************************
|
319
|
+
* PRINT BACKGROUND
|
320
|
+
*********************************************/
|
321
|
+
@media print {
|
322
|
+
.backgrounds {
|
323
|
+
background-color: $backgroundColor;
|
324
|
+
}
|
325
|
+
}
|
@@ -30,8 +30,8 @@ body {
|
|
30
30
|
background: #98bdef;
|
31
31
|
text-shadow: none; }
|
32
32
|
|
33
|
-
.reveal .slides
|
34
|
-
.reveal .slides
|
33
|
+
.reveal .slides section,
|
34
|
+
.reveal .slides section > section {
|
35
35
|
line-height: 1.3;
|
36
36
|
font-weight: inherit; }
|
37
37
|
|
@@ -122,10 +122,6 @@ body {
|
|
122
122
|
.reveal dd {
|
123
123
|
margin-left: 40px; }
|
124
124
|
|
125
|
-
.reveal q,
|
126
|
-
.reveal blockquote {
|
127
|
-
quotes: none; }
|
128
|
-
|
129
125
|
.reveal blockquote {
|
130
126
|
display: block;
|
131
127
|
position: relative;
|
@@ -156,7 +152,8 @@ body {
|
|
156
152
|
box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3); }
|
157
153
|
|
158
154
|
.reveal code {
|
159
|
-
font-family: monospace;
|
155
|
+
font-family: monospace;
|
156
|
+
text-transform: none; }
|
160
157
|
|
161
158
|
.reveal pre code {
|
162
159
|
display: block;
|
@@ -192,10 +189,12 @@ body {
|
|
192
189
|
border-bottom: none; }
|
193
190
|
|
194
191
|
.reveal sup {
|
195
|
-
vertical-align: super;
|
192
|
+
vertical-align: super;
|
193
|
+
font-size: smaller; }
|
196
194
|
|
197
195
|
.reveal sub {
|
198
|
-
vertical-align: sub;
|
196
|
+
vertical-align: sub;
|
197
|
+
font-size: smaller; }
|
199
198
|
|
200
199
|
.reveal small {
|
201
200
|
display: inline-block;
|
@@ -251,42 +250,24 @@ body {
|
|
251
250
|
/*********************************************
|
252
251
|
* NAVIGATION CONTROLS
|
253
252
|
*********************************************/
|
254
|
-
.reveal .controls
|
255
|
-
|
256
|
-
border-right-color: #2a76dd; }
|
257
|
-
|
258
|
-
.reveal .controls .navigate-right,
|
259
|
-
.reveal .controls .navigate-right.enabled {
|
260
|
-
border-left-color: #2a76dd; }
|
261
|
-
|
262
|
-
.reveal .controls .navigate-up,
|
263
|
-
.reveal .controls .navigate-up.enabled {
|
264
|
-
border-bottom-color: #2a76dd; }
|
265
|
-
|
266
|
-
.reveal .controls .navigate-down,
|
267
|
-
.reveal .controls .navigate-down.enabled {
|
268
|
-
border-top-color: #2a76dd; }
|
269
|
-
|
270
|
-
.reveal .controls .navigate-left.enabled:hover {
|
271
|
-
border-right-color: #6ca0e8; }
|
272
|
-
|
273
|
-
.reveal .controls .navigate-right.enabled:hover {
|
274
|
-
border-left-color: #6ca0e8; }
|
275
|
-
|
276
|
-
.reveal .controls .navigate-up.enabled:hover {
|
277
|
-
border-bottom-color: #6ca0e8; }
|
278
|
-
|
279
|
-
.reveal .controls .navigate-down.enabled:hover {
|
280
|
-
border-top-color: #6ca0e8; }
|
253
|
+
.reveal .controls {
|
254
|
+
color: #2a76dd; }
|
281
255
|
|
282
256
|
/*********************************************
|
283
257
|
* PROGRESS BAR
|
284
258
|
*********************************************/
|
285
259
|
.reveal .progress {
|
286
|
-
background: rgba(0, 0, 0, 0.2);
|
260
|
+
background: rgba(0, 0, 0, 0.2);
|
261
|
+
color: #2a76dd; }
|
287
262
|
|
288
263
|
.reveal .progress span {
|
289
|
-
background: #2a76dd;
|
290
264
|
-webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
291
265
|
-moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985);
|
292
266
|
transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); }
|
267
|
+
|
268
|
+
/*********************************************
|
269
|
+
* PRINT BACKGROUND
|
270
|
+
*********************************************/
|
271
|
+
@media print {
|
272
|
+
.backgrounds {
|
273
|
+
background-color: #fff; } }
|
data/files/reveal.js/demo.html
CHANGED
@@ -44,7 +44,7 @@
|
|
44
44
|
<h1>Reveal.js</h1>
|
45
45
|
<h3>The HTML Presentation Framework</h3>
|
46
46
|
<p>
|
47
|
-
<small>Created by <a href="http://hakim.se">Hakim El Hattab</a>
|
47
|
+
<small>Created by <a href="http://hakim.se">Hakim El Hattab</a> and <a href="https://github.com/hakimel/reveal.js/graphs/contributors">contributors</a></small>
|
48
48
|
</p>
|
49
49
|
</section>
|
50
50
|
|
@@ -83,7 +83,7 @@
|
|
83
83
|
<section>
|
84
84
|
<h2>Slides</h2>
|
85
85
|
<p>
|
86
|
-
Not a coder? Not a problem. There's a fully-featured visual editor for authoring these, try it out at <a href="
|
86
|
+
Not a coder? Not a problem. There's a fully-featured visual editor for authoring these, try it out at <a href="https://slides.com" target="_blank">https://slides.com</a>.
|
87
87
|
</p>
|
88
88
|
</section>
|
89
89
|
|
@@ -139,8 +139,14 @@
|
|
139
139
|
<p class="fragment grow">grow</p>
|
140
140
|
<p class="fragment shrink">shrink</p>
|
141
141
|
<p class="fragment fade-out">fade-out</p>
|
142
|
-
<p
|
143
|
-
|
142
|
+
<p>
|
143
|
+
<span style="display: inline-block;" class="fragment fade-right">fade-right, </span>
|
144
|
+
<span style="display: inline-block;" class="fragment fade-up">up, </span>
|
145
|
+
<span style="display: inline-block;" class="fragment fade-down">down, </span>
|
146
|
+
<span style="display: inline-block;" class="fragment fade-left">left</span>
|
147
|
+
</p>
|
148
|
+
<p class="fragment fade-in-then-out">fade-in-then-out</p>
|
149
|
+
<p class="fragment fade-in-then-semi-out">fade-in-then-semi-out</p>
|
144
150
|
<p>Highlight <span class="fragment highlight-red">red</span> <span class="fragment highlight-blue">blue</span> <span class="fragment highlight-green">green</span></p>
|
145
151
|
</section>
|
146
152
|
</section>
|
@@ -295,8 +301,7 @@ function linkify( selector ) {
|
|
295
301
|
<section>
|
296
302
|
<h2>Clever Quotes</h2>
|
297
303
|
<p>
|
298
|
-
These guys come in two forms, inline: <q cite="http://searchservervirtualization.techtarget.com/definition/Our-Favorite-Technology-Quotations">
|
299
|
-
“The nice thing about standards is that there are so many to choose from”</q> and block:
|
304
|
+
These guys come in two forms, inline: <q cite="http://searchservervirtualization.techtarget.com/definition/Our-Favorite-Technology-Quotations">The nice thing about standards is that there are so many to choose from</q> and block:
|
300
305
|
</p>
|
301
306
|
<blockquote cite="http://searchservervirtualization.techtarget.com/definition/Our-Favorite-Technology-Quotations">
|
302
307
|
“For years there has been a theory that millions of monkeys typing at random on millions of typewriters would
|
@@ -370,7 +375,7 @@ Reveal.addEventListener( 'customevent', function() {
|
|
370
375
|
<section style="text-align: left;">
|
371
376
|
<h1>THE END</h1>
|
372
377
|
<p>
|
373
|
-
- <a href="
|
378
|
+
- <a href="https://slides.com">Try the online editor</a> <br>
|
374
379
|
- <a href="https://github.com/hakimel/reveal.js">Source code & documentation</a>
|
375
380
|
</p>
|
376
381
|
</section>
|
@@ -399,6 +404,7 @@ Reveal.addEventListener( 'customevent', function() {
|
|
399
404
|
{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
|
400
405
|
{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
|
401
406
|
{ src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
|
407
|
+
{ src: 'plugin/search/search.js', async: true },
|
402
408
|
{ src: 'plugin/zoom-js/zoom.js', async: true },
|
403
409
|
{ src: 'plugin/notes/notes.js', async: true }
|
404
410
|
]
|
@@ -1,9 +1,9 @@
|
|
1
1
|
/*!
|
2
2
|
* reveal.js
|
3
|
-
* http://
|
3
|
+
* http://revealjs.com
|
4
4
|
* MIT licensed
|
5
5
|
*
|
6
|
-
* Copyright (C)
|
6
|
+
* Copyright (C) 2018 Hakim El Hattab, http://hakim.se
|
7
7
|
*/
|
8
8
|
(function( root, factory ) {
|
9
9
|
if( typeof define === 'function' && define.amd ) {
|
@@ -26,7 +26,7 @@
|
|
26
26
|
var Reveal;
|
27
27
|
|
28
28
|
// The reveal.js version
|
29
|
-
var VERSION = '3.
|
29
|
+
var VERSION = '3.7.0';
|
30
30
|
|
31
31
|
var SLIDES_SELECTOR = '.slides section',
|
32
32
|
HORIZONTAL_SLIDES_SELECTOR = '.slides>section',
|
@@ -49,15 +49,30 @@
|
|
49
49
|
minScale: 0.2,
|
50
50
|
maxScale: 2.0,
|
51
51
|
|
52
|
-
// Display
|
52
|
+
// Display presentation control arrows
|
53
53
|
controls: true,
|
54
54
|
|
55
|
+
// Help the user learn the controls by providing hints, for example by
|
56
|
+
// bouncing the down arrow when they first encounter a vertical slide
|
57
|
+
controlsTutorial: true,
|
58
|
+
|
59
|
+
// Determines where controls appear, "edges" or "bottom-right"
|
60
|
+
controlsLayout: 'bottom-right',
|
61
|
+
|
62
|
+
// Visibility rule for backwards navigation arrows; "faded", "hidden"
|
63
|
+
// or "visible"
|
64
|
+
controlsBackArrows: 'faded',
|
65
|
+
|
55
66
|
// Display a presentation progress bar
|
56
67
|
progress: true,
|
57
68
|
|
58
69
|
// Display the page number of the current slide
|
59
70
|
slideNumber: false,
|
60
71
|
|
72
|
+
// Use 1 based indexing for # links to match slide number (default is zero
|
73
|
+
// based)
|
74
|
+
hashOneBasedIndex: false,
|
75
|
+
|
61
76
|
// Determine which displays to show the slide number on
|
62
77
|
showSlideNumber: 'all',
|
63
78
|
|
@@ -73,6 +88,10 @@
|
|
73
88
|
// Enable the slide overview mode
|
74
89
|
overview: true,
|
75
90
|
|
91
|
+
// Disables the default reveal.js slide layout so that you can use
|
92
|
+
// custom CSS layout
|
93
|
+
disableLayout: false,
|
94
|
+
|
76
95
|
// Vertical centering of slides
|
77
96
|
center: true,
|
78
97
|
|
@@ -91,6 +110,10 @@
|
|
91
110
|
// Turns fragments on and off globally
|
92
111
|
fragments: true,
|
93
112
|
|
113
|
+
// Flags whether to include the current fragment in the URL,
|
114
|
+
// so that reloading brings you to the same fragment position
|
115
|
+
fragmentInURL: false,
|
116
|
+
|
94
117
|
// Flags if the presentation is running in an embedded mode,
|
95
118
|
// i.e. contained within a limited portion of the screen
|
96
119
|
embedded: false,
|
@@ -106,14 +129,16 @@
|
|
106
129
|
showNotes: false,
|
107
130
|
|
108
131
|
// Global override for autolaying embedded media (video/audio/iframe)
|
109
|
-
// - null:
|
110
|
-
// - true:
|
111
|
-
// - false:
|
132
|
+
// - null: Media will only autoplay if data-autoplay is present
|
133
|
+
// - true: All media will autoplay, regardless of individual setting
|
134
|
+
// - false: No media will autoplay, regardless of individual setting
|
112
135
|
autoPlayMedia: null,
|
113
136
|
|
114
|
-
//
|
115
|
-
//
|
116
|
-
//
|
137
|
+
// Controls automatic progression to the next slide
|
138
|
+
// - 0: Auto-sliding only happens if the data-autoslide HTML attribute
|
139
|
+
// is present on the current slide or fragment
|
140
|
+
// - 1+: All slides will progress automatically at the given interval
|
141
|
+
// - false: No auto-sliding, even if data-autoslide is present
|
117
142
|
autoSlide: 0,
|
118
143
|
|
119
144
|
// Stop auto-sliding after user input
|
@@ -122,6 +147,11 @@
|
|
122
147
|
// Use this method for navigation when auto-sliding (defaults to navigateNext)
|
123
148
|
autoSlideMethod: null,
|
124
149
|
|
150
|
+
// Specify the average time in seconds that you think you will spend
|
151
|
+
// presenting each slide. This is used to show a pacing timer in the
|
152
|
+
// speaker view
|
153
|
+
defaultTiming: null,
|
154
|
+
|
125
155
|
// Enable slide navigation via mouse wheel
|
126
156
|
mouseWheel: false,
|
127
157
|
|
@@ -132,6 +162,8 @@
|
|
132
162
|
hideAddressBar: true,
|
133
163
|
|
134
164
|
// Opens links in an iframe preview overlay
|
165
|
+
// Add `data-preview-link` and `data-preview-link="false"` to customise each link
|
166
|
+
// individually
|
135
167
|
previewLinks: false,
|
136
168
|
|
137
169
|
// Exposes the reveal.js API through window.postMessage
|
@@ -158,6 +190,12 @@
|
|
158
190
|
// Parallax background size
|
159
191
|
parallaxBackgroundSize: '', // CSS syntax, e.g. "3000px 2000px"
|
160
192
|
|
193
|
+
// Parallax background repeat
|
194
|
+
parallaxBackgroundRepeat: '', // repeat/repeat-x/repeat-y/no-repeat/initial/inherit
|
195
|
+
|
196
|
+
// Parallax background position
|
197
|
+
parallaxBackgroundPosition: '', // CSS syntax, e.g. "top left"
|
198
|
+
|
161
199
|
// Amount of pixels to move the parallax background per slide step
|
162
200
|
parallaxBackgroundHorizontal: null,
|
163
201
|
parallaxBackgroundVertical: null,
|
@@ -166,6 +204,9 @@
|
|
166
204
|
// to PDF, unlimited by default
|
167
205
|
pdfMaxPagesPerSlide: Number.POSITIVE_INFINITY,
|
168
206
|
|
207
|
+
// Prints each fragment on a separate slide
|
208
|
+
pdfSeparateFragments: true,
|
209
|
+
|
169
210
|
// Offset used to reduce the height of content within exported PDF pages.
|
170
211
|
// This exists to account for environment differences based on how you
|
171
212
|
// print to PDF. CLI printing options, like phantomjs and wkpdf, can end
|
@@ -207,6 +248,10 @@
|
|
207
248
|
|
208
249
|
previousBackground,
|
209
250
|
|
251
|
+
// Remember which directions that the user has navigated towards
|
252
|
+
hasNavigatedRight = false,
|
253
|
+
hasNavigatedDown = false,
|
254
|
+
|
210
255
|
// Slides may hold a data-state attribute which we pick up and apply
|
211
256
|
// as a class to the body. This list contains the combined state of
|
212
257
|
// all current slides.
|
@@ -272,7 +317,10 @@
|
|
272
317
|
'B , .': 'Pause',
|
273
318
|
'F': 'Fullscreen',
|
274
319
|
'ESC, O': 'Slide overview'
|
275
|
-
}
|
320
|
+
},
|
321
|
+
|
322
|
+
// Holds custom key code mappings
|
323
|
+
registeredKeyBindings = {};
|
276
324
|
|
277
325
|
/**
|
278
326
|
* Starts up the presentation if the client is capable.
|
@@ -374,13 +422,13 @@
|
|
374
422
|
|
375
423
|
}
|
376
424
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
425
|
+
/**
|
426
|
+
* Loads the dependencies of reveal.js. Dependencies are
|
427
|
+
* defined via the configuration option 'dependencies'
|
428
|
+
* and will be loaded prior to starting/binding reveal.js.
|
429
|
+
* Some dependencies may have an 'async' flag, if so they
|
430
|
+
* will load after reveal.js has been started up.
|
431
|
+
*/
|
384
432
|
function load() {
|
385
433
|
|
386
434
|
var scripts = [],
|
@@ -398,7 +446,7 @@
|
|
398
446
|
}
|
399
447
|
|
400
448
|
function loadScript( s ) {
|
401
|
-
head.ready( s.src.match( /([\w\d_\-]*)\.?js
|
449
|
+
head.ready( s.src.match( /([\w\d_\-]*)\.?js(\?[\w\d.=&]*)?$|[^\\\/]*$/i )[0], function() {
|
402
450
|
// Extension may contain callback functions
|
403
451
|
if( typeof s.callback === 'function' ) {
|
404
452
|
s.callback.apply( this );
|
@@ -444,6 +492,8 @@
|
|
444
492
|
*/
|
445
493
|
function start() {
|
446
494
|
|
495
|
+
loaded = true;
|
496
|
+
|
447
497
|
// Make sure we've got all the DOM elements we need
|
448
498
|
setupDOM();
|
449
499
|
|
@@ -471,8 +521,6 @@
|
|
471
521
|
// Enable transitions now that we're loaded
|
472
522
|
dom.slides.classList.remove( 'no-transition' );
|
473
523
|
|
474
|
-
loaded = true;
|
475
|
-
|
476
524
|
dom.wrapper.classList.add( 'ready' );
|
477
525
|
|
478
526
|
dispatchEvent( 'ready', {
|
@@ -508,6 +556,20 @@
|
|
508
556
|
// Prevent transitions while we're loading
|
509
557
|
dom.slides.classList.add( 'no-transition' );
|
510
558
|
|
559
|
+
if( isMobileDevice ) {
|
560
|
+
dom.wrapper.classList.add( 'no-hover' );
|
561
|
+
}
|
562
|
+
else {
|
563
|
+
dom.wrapper.classList.remove( 'no-hover' );
|
564
|
+
}
|
565
|
+
|
566
|
+
if( /iphone/gi.test( UA ) ) {
|
567
|
+
dom.wrapper.classList.add( 'ua-iphone' );
|
568
|
+
}
|
569
|
+
else {
|
570
|
+
dom.wrapper.classList.remove( 'ua-iphone' );
|
571
|
+
}
|
572
|
+
|
511
573
|
// Background element
|
512
574
|
dom.background = createSingletonNode( dom.wrapper, 'div', 'backgrounds', null );
|
513
575
|
|
@@ -516,11 +578,11 @@
|
|
516
578
|
dom.progressbar = dom.progress.querySelector( 'span' );
|
517
579
|
|
518
580
|
// Arrow controls
|
519
|
-
createSingletonNode( dom.wrapper, 'aside', 'controls',
|
520
|
-
'<button class="navigate-left" aria-label="previous slide"></button>' +
|
521
|
-
'<button class="navigate-right" aria-label="next slide"></button>' +
|
522
|
-
'<button class="navigate-up" aria-label="above slide"></button>' +
|
523
|
-
'<button class="navigate-down" aria-label="below slide"></button>' );
|
581
|
+
dom.controls = createSingletonNode( dom.wrapper, 'aside', 'controls',
|
582
|
+
'<button class="navigate-left" aria-label="previous slide"><div class="controls-arrow"></div></button>' +
|
583
|
+
'<button class="navigate-right" aria-label="next slide"><div class="controls-arrow"></div></button>' +
|
584
|
+
'<button class="navigate-up" aria-label="above slide"><div class="controls-arrow"></div></button>' +
|
585
|
+
'<button class="navigate-down" aria-label="below slide"><div class="controls-arrow"></div></button>' );
|
524
586
|
|
525
587
|
// Slide number
|
526
588
|
dom.slideNumber = createSingletonNode( dom.wrapper, 'div', 'slide-number', '' );
|
@@ -531,10 +593,8 @@
|
|
531
593
|
dom.speakerNotes.setAttribute( 'tabindex', '0' );
|
532
594
|
|
533
595
|
// Overlay graphic which is displayed during the paused mode
|
534
|
-
createSingletonNode( dom.wrapper, 'div', 'pause-overlay',
|
535
|
-
|
536
|
-
// Cache references to elements
|
537
|
-
dom.controls = document.querySelector( '.reveal .controls' );
|
596
|
+
dom.pauseOverlay = createSingletonNode( dom.wrapper, 'div', 'pause-overlay', '<button class="resume-button">Resume presentation</button>' );
|
597
|
+
dom.resumeButton = dom.pauseOverlay.querySelector( '.resume-button' );
|
538
598
|
|
539
599
|
dom.wrapper.setAttribute( 'role', 'application' );
|
540
600
|
|
@@ -546,6 +606,10 @@
|
|
546
606
|
dom.controlsPrev = toArray( document.querySelectorAll( '.navigate-prev' ) );
|
547
607
|
dom.controlsNext = toArray( document.querySelectorAll( '.navigate-next' ) );
|
548
608
|
|
609
|
+
// The right and down arrows in the standard reveal.js controls
|
610
|
+
dom.controlsRightArrow = dom.controls.querySelector( '.navigate-right' );
|
611
|
+
dom.controlsDownArrow = dom.controls.querySelector( '.navigate-down' );
|
612
|
+
|
549
613
|
dom.statusDiv = createStatusDiv();
|
550
614
|
}
|
551
615
|
|
@@ -727,13 +791,58 @@
|
|
727
791
|
numberElement.innerHTML = formatSlideNumber( slideNumberH, '.', slideNumberV );
|
728
792
|
page.appendChild( numberElement );
|
729
793
|
}
|
730
|
-
}
|
731
794
|
|
732
|
-
|
795
|
+
// Copy page and show fragments one after another
|
796
|
+
if( config.pdfSeparateFragments ) {
|
797
|
+
|
798
|
+
// Each fragment 'group' is an array containing one or more
|
799
|
+
// fragments. Multiple fragments that appear at the same time
|
800
|
+
// are part of the same group.
|
801
|
+
var fragmentGroups = sortFragments( page.querySelectorAll( '.fragment' ), true );
|
802
|
+
|
803
|
+
var previousFragmentStep;
|
804
|
+
var previousPage;
|
805
|
+
|
806
|
+
fragmentGroups.forEach( function( fragments ) {
|
807
|
+
|
808
|
+
// Remove 'current-fragment' from the previous group
|
809
|
+
if( previousFragmentStep ) {
|
810
|
+
previousFragmentStep.forEach( function( fragment ) {
|
811
|
+
fragment.classList.remove( 'current-fragment' );
|
812
|
+
} );
|
813
|
+
}
|
814
|
+
|
815
|
+
// Show the fragments for the current index
|
816
|
+
fragments.forEach( function( fragment ) {
|
817
|
+
fragment.classList.add( 'visible', 'current-fragment' );
|
818
|
+
} );
|
819
|
+
|
820
|
+
// Create a separate page for the current fragment state
|
821
|
+
var clonedPage = page.cloneNode( true );
|
822
|
+
page.parentNode.insertBefore( clonedPage, ( previousPage || page ).nextSibling );
|
823
|
+
|
824
|
+
previousFragmentStep = fragments;
|
825
|
+
previousPage = clonedPage;
|
826
|
+
|
827
|
+
} );
|
828
|
+
|
829
|
+
// Reset the first/original page so that all fragments are hidden
|
830
|
+
fragmentGroups.forEach( function( fragments ) {
|
831
|
+
fragments.forEach( function( fragment ) {
|
832
|
+
fragment.classList.remove( 'visible', 'current-fragment' );
|
833
|
+
} );
|
834
|
+
} );
|
835
|
+
|
836
|
+
}
|
837
|
+
// Show all fragments
|
838
|
+
else {
|
839
|
+
toArray( page.querySelectorAll( '.fragment:not(.fade-out)' ) ).forEach( function( fragment ) {
|
840
|
+
fragment.classList.add( 'visible' );
|
841
|
+
} );
|
842
|
+
}
|
843
|
+
|
844
|
+
}
|
733
845
|
|
734
|
-
// Show all fragments
|
735
|
-
toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR + ' .fragment' ) ).forEach( function( fragment ) {
|
736
|
-
fragment.classList.add( 'visible' );
|
737
846
|
} );
|
738
847
|
|
739
848
|
// Notify subscribers that the PDF layout is good to go
|
@@ -789,7 +898,7 @@
|
|
789
898
|
|
790
899
|
// If no node was found, create it now
|
791
900
|
var node = document.createElement( tagname );
|
792
|
-
node.
|
901
|
+
node.className = classname;
|
793
902
|
if( typeof innerHTML === 'string' ) {
|
794
903
|
node.innerHTML = innerHTML;
|
795
904
|
}
|
@@ -833,6 +942,8 @@
|
|
833
942
|
|
834
943
|
dom.background.style.backgroundImage = 'url("' + config.parallaxBackgroundImage + '")';
|
835
944
|
dom.background.style.backgroundSize = config.parallaxBackgroundSize;
|
945
|
+
dom.background.style.backgroundRepeat = config.parallaxBackgroundRepeat;
|
946
|
+
dom.background.style.backgroundPosition = config.parallaxBackgroundPosition;
|
836
947
|
|
837
948
|
// Make sure the below properties are set on the element - these properties are
|
838
949
|
// needed for proper transitions to be set on the element via CSS. To remove
|
@@ -862,6 +973,57 @@
|
|
862
973
|
*/
|
863
974
|
function createBackground( slide, container ) {
|
864
975
|
|
976
|
+
|
977
|
+
// Main slide background element
|
978
|
+
var element = document.createElement( 'div' );
|
979
|
+
element.className = 'slide-background ' + slide.className.replace( /present|past|future/, '' );
|
980
|
+
|
981
|
+
// Inner background element that wraps images/videos/iframes
|
982
|
+
var contentElement = document.createElement( 'div' );
|
983
|
+
contentElement.className = 'slide-background-content';
|
984
|
+
|
985
|
+
element.appendChild( contentElement );
|
986
|
+
container.appendChild( element );
|
987
|
+
|
988
|
+
slide.slideBackgroundElement = element;
|
989
|
+
slide.slideBackgroundContentElement = contentElement;
|
990
|
+
|
991
|
+
// Syncs the background to reflect all current background settings
|
992
|
+
syncBackground( slide );
|
993
|
+
|
994
|
+
return element;
|
995
|
+
|
996
|
+
}
|
997
|
+
|
998
|
+
/**
|
999
|
+
* Renders all of the visual properties of a slide background
|
1000
|
+
* based on the various background attributes.
|
1001
|
+
*
|
1002
|
+
* @param {HTMLElement} slide
|
1003
|
+
*/
|
1004
|
+
function syncBackground( slide ) {
|
1005
|
+
|
1006
|
+
var element = slide.slideBackgroundElement,
|
1007
|
+
contentElement = slide.slideBackgroundContentElement;
|
1008
|
+
|
1009
|
+
// Reset the prior background state in case this is not the
|
1010
|
+
// initial sync
|
1011
|
+
slide.classList.remove( 'has-dark-background' );
|
1012
|
+
slide.classList.remove( 'has-light-background' );
|
1013
|
+
|
1014
|
+
element.removeAttribute( 'data-loaded' );
|
1015
|
+
element.removeAttribute( 'data-background-hash' );
|
1016
|
+
element.removeAttribute( 'data-background-size' );
|
1017
|
+
element.removeAttribute( 'data-background-transition' );
|
1018
|
+
element.style.backgroundColor = '';
|
1019
|
+
|
1020
|
+
contentElement.style.backgroundSize = '';
|
1021
|
+
contentElement.style.backgroundRepeat = '';
|
1022
|
+
contentElement.style.backgroundPosition = '';
|
1023
|
+
contentElement.style.backgroundImage = '';
|
1024
|
+
contentElement.style.opacity = '';
|
1025
|
+
contentElement.innerHTML = '';
|
1026
|
+
|
865
1027
|
var data = {
|
866
1028
|
background: slide.getAttribute( 'data-background' ),
|
867
1029
|
backgroundSize: slide.getAttribute( 'data-background-size' ),
|
@@ -871,17 +1033,13 @@
|
|
871
1033
|
backgroundColor: slide.getAttribute( 'data-background-color' ),
|
872
1034
|
backgroundRepeat: slide.getAttribute( 'data-background-repeat' ),
|
873
1035
|
backgroundPosition: slide.getAttribute( 'data-background-position' ),
|
874
|
-
backgroundTransition: slide.getAttribute( 'data-background-transition' )
|
1036
|
+
backgroundTransition: slide.getAttribute( 'data-background-transition' ),
|
1037
|
+
backgroundOpacity: slide.getAttribute( 'data-background-opacity' )
|
875
1038
|
};
|
876
1039
|
|
877
|
-
var element = document.createElement( 'div' );
|
878
|
-
|
879
|
-
// Carry over custom classes from the slide to the background
|
880
|
-
element.className = 'slide-background ' + slide.className.replace( /present|past|future/, '' );
|
881
|
-
|
882
1040
|
if( data.background ) {
|
883
1041
|
// Auto-wrap image urls in url(...)
|
884
|
-
if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp)([
|
1042
|
+
if( /^(http|file|\/\/)/gi.test( data.background ) || /\.(svg|png|jpg|jpeg|gif|bmp)([?#\s]|$)/gi.test( data.background ) ) {
|
885
1043
|
slide.setAttribute( 'data-background-image', data.background );
|
886
1044
|
}
|
887
1045
|
else {
|
@@ -901,24 +1059,20 @@
|
|
901
1059
|
data.backgroundColor +
|
902
1060
|
data.backgroundRepeat +
|
903
1061
|
data.backgroundPosition +
|
904
|
-
data.backgroundTransition
|
1062
|
+
data.backgroundTransition +
|
1063
|
+
data.backgroundOpacity );
|
905
1064
|
}
|
906
1065
|
|
907
1066
|
// Additional and optional background properties
|
908
|
-
if( data.backgroundSize ) element.style.backgroundSize = data.backgroundSize;
|
909
1067
|
if( data.backgroundSize ) element.setAttribute( 'data-background-size', data.backgroundSize );
|
910
1068
|
if( data.backgroundColor ) element.style.backgroundColor = data.backgroundColor;
|
911
|
-
if( data.backgroundRepeat ) element.style.backgroundRepeat = data.backgroundRepeat;
|
912
|
-
if( data.backgroundPosition ) element.style.backgroundPosition = data.backgroundPosition;
|
913
1069
|
if( data.backgroundTransition ) element.setAttribute( 'data-background-transition', data.backgroundTransition );
|
914
1070
|
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
slide.slideBackgroundElement = element;
|
1071
|
+
// Background image options are set on the content wrapper
|
1072
|
+
if( data.backgroundSize ) contentElement.style.backgroundSize = data.backgroundSize;
|
1073
|
+
if( data.backgroundRepeat ) contentElement.style.backgroundRepeat = data.backgroundRepeat;
|
1074
|
+
if( data.backgroundPosition ) contentElement.style.backgroundPosition = data.backgroundPosition;
|
1075
|
+
if( data.backgroundOpacity ) contentElement.style.opacity = data.backgroundOpacity;
|
922
1076
|
|
923
1077
|
// If this slide has a background color, add a class that
|
924
1078
|
// signals if it is light or dark. If the slide has no background
|
@@ -940,8 +1094,6 @@
|
|
940
1094
|
}
|
941
1095
|
}
|
942
1096
|
|
943
|
-
return element;
|
944
|
-
|
945
1097
|
}
|
946
1098
|
|
947
1099
|
/**
|
@@ -982,14 +1134,22 @@
|
|
982
1134
|
*/
|
983
1135
|
function configure( options ) {
|
984
1136
|
|
985
|
-
var
|
986
|
-
|
987
|
-
dom.wrapper.classList.remove( config.transition );
|
1137
|
+
var oldTransition = config.transition;
|
988
1138
|
|
989
1139
|
// New config options may be passed when this method
|
990
1140
|
// is invoked through the API after initialization
|
991
1141
|
if( typeof options === 'object' ) extend( config, options );
|
992
1142
|
|
1143
|
+
// Abort if reveal.js hasn't finished loading, config
|
1144
|
+
// changes will be applied automatically once loading
|
1145
|
+
// finishes
|
1146
|
+
if( loaded === false ) return;
|
1147
|
+
|
1148
|
+
var numberOfSlides = dom.wrapper.querySelectorAll( SLIDES_SELECTOR ).length;
|
1149
|
+
|
1150
|
+
// Remove the previously configured transition class
|
1151
|
+
dom.wrapper.classList.remove( oldTransition );
|
1152
|
+
|
993
1153
|
// Force linear transition based on browser capabilities
|
994
1154
|
if( features.transforms3d === false ) config.transition = 'linear';
|
995
1155
|
|
@@ -1001,6 +1161,9 @@
|
|
1001
1161
|
dom.controls.style.display = config.controls ? 'block' : 'none';
|
1002
1162
|
dom.progress.style.display = config.progress ? 'block' : 'none';
|
1003
1163
|
|
1164
|
+
dom.controls.setAttribute( 'data-controls-layout', config.controlsLayout );
|
1165
|
+
dom.controls.setAttribute( 'data-controls-back-arrows', config.controlsBackArrows );
|
1166
|
+
|
1004
1167
|
if( config.shuffle ) {
|
1005
1168
|
shuffle();
|
1006
1169
|
}
|
@@ -1025,12 +1188,8 @@
|
|
1025
1188
|
}
|
1026
1189
|
|
1027
1190
|
if( config.showNotes ) {
|
1028
|
-
dom.speakerNotes.classList.add( 'visible' );
|
1029
1191
|
dom.speakerNotes.setAttribute( 'data-layout', typeof config.showNotes === 'string' ? config.showNotes : 'inline' );
|
1030
1192
|
}
|
1031
|
-
else {
|
1032
|
-
dom.speakerNotes.classList.remove( 'visible' );
|
1033
|
-
}
|
1034
1193
|
|
1035
1194
|
if( config.mouseWheel ) {
|
1036
1195
|
document.addEventListener( 'DOMMouseScroll', onDocumentMouseScroll, false ); // FF
|
@@ -1111,13 +1270,8 @@
|
|
1111
1270
|
window.addEventListener( 'resize', onWindowResize, false );
|
1112
1271
|
|
1113
1272
|
if( config.touch ) {
|
1114
|
-
|
1115
|
-
|
1116
|
-
dom.wrapper.addEventListener( 'touchend', onTouchEnd, false );
|
1117
|
-
|
1118
|
-
// Support pointer-style touch interaction as well
|
1119
|
-
if( window.navigator.pointerEnabled ) {
|
1120
|
-
// IE 11 uses un-prefixed version of pointer events
|
1273
|
+
if( 'onpointerdown' in window ) {
|
1274
|
+
// Use W3C pointer events
|
1121
1275
|
dom.wrapper.addEventListener( 'pointerdown', onPointerDown, false );
|
1122
1276
|
dom.wrapper.addEventListener( 'pointermove', onPointerMove, false );
|
1123
1277
|
dom.wrapper.addEventListener( 'pointerup', onPointerUp, false );
|
@@ -1128,6 +1282,12 @@
|
|
1128
1282
|
dom.wrapper.addEventListener( 'MSPointerMove', onPointerMove, false );
|
1129
1283
|
dom.wrapper.addEventListener( 'MSPointerUp', onPointerUp, false );
|
1130
1284
|
}
|
1285
|
+
else {
|
1286
|
+
// Fall back to touch events
|
1287
|
+
dom.wrapper.addEventListener( 'touchstart', onTouchStart, false );
|
1288
|
+
dom.wrapper.addEventListener( 'touchmove', onTouchMove, false );
|
1289
|
+
dom.wrapper.addEventListener( 'touchend', onTouchEnd, false );
|
1290
|
+
}
|
1131
1291
|
}
|
1132
1292
|
|
1133
1293
|
if( config.keyboard ) {
|
@@ -1139,6 +1299,8 @@
|
|
1139
1299
|
dom.progress.addEventListener( 'click', onProgressClicked, false );
|
1140
1300
|
}
|
1141
1301
|
|
1302
|
+
dom.resumeButton.addEventListener( 'click', resume, false );
|
1303
|
+
|
1142
1304
|
if( config.focusBodyOnPageVisibilityChange ) {
|
1143
1305
|
var visibilityChange;
|
1144
1306
|
|
@@ -1190,22 +1352,19 @@
|
|
1190
1352
|
window.removeEventListener( 'hashchange', onWindowHashChange, false );
|
1191
1353
|
window.removeEventListener( 'resize', onWindowResize, false );
|
1192
1354
|
|
1355
|
+
dom.wrapper.removeEventListener( 'pointerdown', onPointerDown, false );
|
1356
|
+
dom.wrapper.removeEventListener( 'pointermove', onPointerMove, false );
|
1357
|
+
dom.wrapper.removeEventListener( 'pointerup', onPointerUp, false );
|
1358
|
+
|
1359
|
+
dom.wrapper.removeEventListener( 'MSPointerDown', onPointerDown, false );
|
1360
|
+
dom.wrapper.removeEventListener( 'MSPointerMove', onPointerMove, false );
|
1361
|
+
dom.wrapper.removeEventListener( 'MSPointerUp', onPointerUp, false );
|
1362
|
+
|
1193
1363
|
dom.wrapper.removeEventListener( 'touchstart', onTouchStart, false );
|
1194
1364
|
dom.wrapper.removeEventListener( 'touchmove', onTouchMove, false );
|
1195
1365
|
dom.wrapper.removeEventListener( 'touchend', onTouchEnd, false );
|
1196
1366
|
|
1197
|
-
|
1198
|
-
if( window.navigator.pointerEnabled ) {
|
1199
|
-
dom.wrapper.removeEventListener( 'pointerdown', onPointerDown, false );
|
1200
|
-
dom.wrapper.removeEventListener( 'pointermove', onPointerMove, false );
|
1201
|
-
dom.wrapper.removeEventListener( 'pointerup', onPointerUp, false );
|
1202
|
-
}
|
1203
|
-
// IE10
|
1204
|
-
else if( window.navigator.msPointerEnabled ) {
|
1205
|
-
dom.wrapper.removeEventListener( 'MSPointerDown', onPointerDown, false );
|
1206
|
-
dom.wrapper.removeEventListener( 'MSPointerMove', onPointerMove, false );
|
1207
|
-
dom.wrapper.removeEventListener( 'MSPointerUp', onPointerUp, false );
|
1208
|
-
}
|
1367
|
+
dom.resumeButton.removeEventListener( 'click', resume, false );
|
1209
1368
|
|
1210
1369
|
if ( config.progress && dom.progress ) {
|
1211
1370
|
dom.progress.removeEventListener( 'click', onProgressClicked, false );
|
@@ -1222,6 +1381,38 @@
|
|
1222
1381
|
|
1223
1382
|
}
|
1224
1383
|
|
1384
|
+
/**
|
1385
|
+
* Add a custom key binding with optional description to
|
1386
|
+
* be added to the help screen.
|
1387
|
+
*/
|
1388
|
+
function addKeyBinding( binding, callback ) {
|
1389
|
+
|
1390
|
+
if( typeof binding === 'object' && binding.keyCode ) {
|
1391
|
+
registeredKeyBindings[binding.keyCode] = {
|
1392
|
+
callback: callback,
|
1393
|
+
key: binding.key,
|
1394
|
+
description: binding.description
|
1395
|
+
};
|
1396
|
+
}
|
1397
|
+
else {
|
1398
|
+
registeredKeyBindings[binding] = {
|
1399
|
+
callback: callback,
|
1400
|
+
key: null,
|
1401
|
+
description: null
|
1402
|
+
};
|
1403
|
+
}
|
1404
|
+
|
1405
|
+
}
|
1406
|
+
|
1407
|
+
/**
|
1408
|
+
* Removes the specified custom key binding.
|
1409
|
+
*/
|
1410
|
+
function removeKeyBinding( keyCode ) {
|
1411
|
+
|
1412
|
+
delete registeredKeyBindings[keyCode];
|
1413
|
+
|
1414
|
+
}
|
1415
|
+
|
1225
1416
|
/**
|
1226
1417
|
* Extend object a with the properties of object b.
|
1227
1418
|
* If there's a conflict, object b takes precedence.
|
@@ -1235,6 +1426,8 @@
|
|
1235
1426
|
a[ i ] = b[ i ];
|
1236
1427
|
}
|
1237
1428
|
|
1429
|
+
return a;
|
1430
|
+
|
1238
1431
|
}
|
1239
1432
|
|
1240
1433
|
/**
|
@@ -1261,7 +1454,7 @@
|
|
1261
1454
|
if( value === 'null' ) return null;
|
1262
1455
|
else if( value === 'true' ) return true;
|
1263
1456
|
else if( value === 'false' ) return false;
|
1264
|
-
else if( value.match(
|
1457
|
+
else if( value.match( /^-?[\d\.]+$/ ) ) return parseFloat( value );
|
1265
1458
|
}
|
1266
1459
|
|
1267
1460
|
return value;
|
@@ -1497,6 +1690,15 @@
|
|
1497
1690
|
|
1498
1691
|
}
|
1499
1692
|
|
1693
|
+
/**
|
1694
|
+
* Check if this instance is being used to print a PDF with fragments.
|
1695
|
+
*/
|
1696
|
+
function isPrintingPDFFragments() {
|
1697
|
+
|
1698
|
+
return ( /print-pdf-fragments/gi ).test( window.location.search );
|
1699
|
+
|
1700
|
+
}
|
1701
|
+
|
1500
1702
|
/**
|
1501
1703
|
* Hides the address bar if we're on a mobile device.
|
1502
1704
|
*/
|
@@ -1707,6 +1909,13 @@
|
|
1707
1909
|
html += '<tr><td>' + key + '</td><td>' + keyboardShortcuts[ key ] + '</td></tr>';
|
1708
1910
|
}
|
1709
1911
|
|
1912
|
+
// Add custom key bindings that have associated descriptions
|
1913
|
+
for( var binding in registeredKeyBindings ) {
|
1914
|
+
if( registeredKeyBindings[binding].key && registeredKeyBindings[binding].description ) {
|
1915
|
+
html += '<tr><td>' + registeredKeyBindings[binding].key + '</td><td>' + registeredKeyBindings[binding].description + '</td></tr>';
|
1916
|
+
}
|
1917
|
+
}
|
1918
|
+
|
1710
1919
|
html += '</table>';
|
1711
1920
|
|
1712
1921
|
dom.overlay.innerHTML = [
|
@@ -1751,76 +1960,80 @@
|
|
1751
1960
|
|
1752
1961
|
if( dom.wrapper && !isPrintingPDF() ) {
|
1753
1962
|
|
1754
|
-
|
1963
|
+
if( !config.disableLayout ) {
|
1755
1964
|
|
1756
|
-
|
1757
|
-
layoutSlideContents( config.width, config.height );
|
1965
|
+
var size = getComputedSlideSize();
|
1758
1966
|
|
1759
|
-
|
1760
|
-
|
1967
|
+
// Layout the contents of the slides
|
1968
|
+
layoutSlideContents( config.width, config.height );
|
1761
1969
|
|
1762
|
-
|
1763
|
-
|
1970
|
+
dom.slides.style.width = size.width + 'px';
|
1971
|
+
dom.slides.style.height = size.height + 'px';
|
1764
1972
|
|
1765
|
-
|
1766
|
-
|
1767
|
-
scale = Math.min( scale, config.maxScale );
|
1973
|
+
// Determine scale of content to fit within available space
|
1974
|
+
scale = Math.min( size.presentationWidth / size.width, size.presentationHeight / size.height );
|
1768
1975
|
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
transformSlides( { layout: '' } );
|
1777
|
-
}
|
1778
|
-
else {
|
1779
|
-
// Prefer zoom for scaling up so that content remains crisp.
|
1780
|
-
// Don't use zoom to scale down since that can lead to shifts
|
1781
|
-
// in text layout/line breaks.
|
1782
|
-
if( scale > 1 && features.zoom ) {
|
1783
|
-
dom.slides.style.zoom = scale;
|
1976
|
+
// Respect max/min scale settings
|
1977
|
+
scale = Math.max( scale, config.minScale );
|
1978
|
+
scale = Math.min( scale, config.maxScale );
|
1979
|
+
|
1980
|
+
// Don't apply any scaling styles if scale is 1
|
1981
|
+
if( scale === 1 ) {
|
1982
|
+
dom.slides.style.zoom = '';
|
1784
1983
|
dom.slides.style.left = '';
|
1785
1984
|
dom.slides.style.top = '';
|
1786
1985
|
dom.slides.style.bottom = '';
|
1787
1986
|
dom.slides.style.right = '';
|
1788
1987
|
transformSlides( { layout: '' } );
|
1789
1988
|
}
|
1790
|
-
// Apply scale transform as a fallback
|
1791
1989
|
else {
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1990
|
+
// Prefer zoom for scaling up so that content remains crisp.
|
1991
|
+
// Don't use zoom to scale down since that can lead to shifts
|
1992
|
+
// in text layout/line breaks.
|
1993
|
+
if( scale > 1 && features.zoom ) {
|
1994
|
+
dom.slides.style.zoom = scale;
|
1995
|
+
dom.slides.style.left = '';
|
1996
|
+
dom.slides.style.top = '';
|
1997
|
+
dom.slides.style.bottom = '';
|
1998
|
+
dom.slides.style.right = '';
|
1999
|
+
transformSlides( { layout: '' } );
|
2000
|
+
}
|
2001
|
+
// Apply scale transform as a fallback
|
2002
|
+
else {
|
2003
|
+
dom.slides.style.zoom = '';
|
2004
|
+
dom.slides.style.left = '50%';
|
2005
|
+
dom.slides.style.top = '50%';
|
2006
|
+
dom.slides.style.bottom = 'auto';
|
2007
|
+
dom.slides.style.right = 'auto';
|
2008
|
+
transformSlides( { layout: 'translate(-50%, -50%) scale('+ scale +')' } );
|
2009
|
+
}
|
1798
2010
|
}
|
1799
|
-
}
|
1800
2011
|
|
1801
|
-
|
1802
|
-
|
2012
|
+
// Select all slides, vertical and horizontal
|
2013
|
+
var slides = toArray( dom.wrapper.querySelectorAll( SLIDES_SELECTOR ) );
|
1803
2014
|
|
1804
|
-
|
1805
|
-
|
2015
|
+
for( var i = 0, len = slides.length; i < len; i++ ) {
|
2016
|
+
var slide = slides[ i ];
|
1806
2017
|
|
1807
|
-
|
1808
|
-
|
1809
|
-
|
1810
|
-
|
2018
|
+
// Don't bother updating invisible slides
|
2019
|
+
if( slide.style.display === 'none' ) {
|
2020
|
+
continue;
|
2021
|
+
}
|
1811
2022
|
|
1812
|
-
|
1813
|
-
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
2023
|
+
if( config.center || slide.classList.contains( 'center' ) ) {
|
2024
|
+
// Vertical stacks are not centred since their section
|
2025
|
+
// children will be
|
2026
|
+
if( slide.classList.contains( 'stack' ) ) {
|
2027
|
+
slide.style.top = 0;
|
2028
|
+
}
|
2029
|
+
else {
|
2030
|
+
slide.style.top = Math.max( ( size.height - slide.scrollHeight ) / 2, 0 ) + 'px';
|
2031
|
+
}
|
1817
2032
|
}
|
1818
2033
|
else {
|
1819
|
-
slide.style.top =
|
2034
|
+
slide.style.top = '';
|
1820
2035
|
}
|
1821
|
-
|
1822
|
-
else {
|
1823
|
-
slide.style.top = '';
|
2036
|
+
|
1824
2037
|
}
|
1825
2038
|
|
1826
2039
|
}
|
@@ -2146,6 +2359,41 @@
|
|
2146
2359
|
|
2147
2360
|
}
|
2148
2361
|
|
2362
|
+
/**
|
2363
|
+
* Return a hash URL that will resolve to the current slide location.
|
2364
|
+
*/
|
2365
|
+
function locationHash() {
|
2366
|
+
|
2367
|
+
var url = '/';
|
2368
|
+
|
2369
|
+
// Attempt to create a named link based on the slide's ID
|
2370
|
+
var id = currentSlide ? currentSlide.getAttribute( 'id' ) : null;
|
2371
|
+
if( id ) {
|
2372
|
+
id = encodeURIComponent( id );
|
2373
|
+
}
|
2374
|
+
|
2375
|
+
var indexf;
|
2376
|
+
if( config.fragmentInURL ) {
|
2377
|
+
indexf = getIndices().f;
|
2378
|
+
}
|
2379
|
+
|
2380
|
+
// If the current slide has an ID, use that as a named link,
|
2381
|
+
// but we don't support named links with a fragment index
|
2382
|
+
if( typeof id === 'string' && id.length && indexf === undefined ) {
|
2383
|
+
url = '/' + id;
|
2384
|
+
}
|
2385
|
+
// Otherwise use the /h/v index
|
2386
|
+
else {
|
2387
|
+
var hashIndexBase = config.hashOneBasedIndex ? 1 : 0;
|
2388
|
+
if( indexh > 0 || indexv > 0 || indexf !== undefined ) url += indexh + hashIndexBase;
|
2389
|
+
if( indexv > 0 || indexf !== undefined ) url += '/' + (indexv + hashIndexBase );
|
2390
|
+
if( indexf !== undefined ) url += '/' + indexf;
|
2391
|
+
}
|
2392
|
+
|
2393
|
+
return url;
|
2394
|
+
|
2395
|
+
}
|
2396
|
+
|
2149
2397
|
/**
|
2150
2398
|
* Checks if the current or specified slide is vertical
|
2151
2399
|
* (nested within another slide).
|
@@ -2370,16 +2618,7 @@
|
|
2370
2618
|
|
2371
2619
|
// Dispatch an event if the slide changed
|
2372
2620
|
var slideChanged = ( indexh !== indexhBefore || indexv !== indexvBefore );
|
2373
|
-
if(
|
2374
|
-
dispatchEvent( 'slidechanged', {
|
2375
|
-
'indexh': indexh,
|
2376
|
-
'indexv': indexv,
|
2377
|
-
'previousSlide': previousSlide,
|
2378
|
-
'currentSlide': currentSlide,
|
2379
|
-
'origin': o
|
2380
|
-
} );
|
2381
|
-
}
|
2382
|
-
else {
|
2621
|
+
if (!slideChanged) {
|
2383
2622
|
// Ensure that the previous slide is never the same as the current
|
2384
2623
|
previousSlide = null;
|
2385
2624
|
}
|
@@ -2387,7 +2626,7 @@
|
|
2387
2626
|
// Solves an edge case where the previous slide maintains the
|
2388
2627
|
// 'present' class when navigating between adjacent vertical
|
2389
2628
|
// stacks
|
2390
|
-
if( previousSlide ) {
|
2629
|
+
if( previousSlide && previousSlide !== currentSlide ) {
|
2391
2630
|
previousSlide.classList.remove( 'present' );
|
2392
2631
|
previousSlide.setAttribute( 'aria-hidden', 'true' );
|
2393
2632
|
|
@@ -2407,6 +2646,16 @@
|
|
2407
2646
|
}
|
2408
2647
|
}
|
2409
2648
|
|
2649
|
+
if( slideChanged ) {
|
2650
|
+
dispatchEvent( 'slidechanged', {
|
2651
|
+
'indexh': indexh,
|
2652
|
+
'indexv': indexv,
|
2653
|
+
'previousSlide': previousSlide,
|
2654
|
+
'currentSlide': currentSlide,
|
2655
|
+
'origin': o
|
2656
|
+
} );
|
2657
|
+
}
|
2658
|
+
|
2410
2659
|
// Handle embedded content
|
2411
2660
|
if( slideChanged || !previousSlide ) {
|
2412
2661
|
stopEmbeddedContent( previousSlide );
|
@@ -2463,13 +2712,14 @@
|
|
2463
2712
|
updateSlideNumber();
|
2464
2713
|
updateSlidesVisibility();
|
2465
2714
|
updateBackground( true );
|
2715
|
+
updateNotesVisibility();
|
2466
2716
|
updateNotes();
|
2467
2717
|
|
2468
2718
|
formatEmbeddedContent();
|
2469
2719
|
|
2470
2720
|
// Start or stop embedded content depending on global config
|
2471
2721
|
if( config.autoPlayMedia === false ) {
|
2472
|
-
stopEmbeddedContent( currentSlide );
|
2722
|
+
stopEmbeddedContent( currentSlide, { unloadIframes: false } );
|
2473
2723
|
}
|
2474
2724
|
else {
|
2475
2725
|
startEmbeddedContent( currentSlide );
|
@@ -2481,6 +2731,41 @@
|
|
2481
2731
|
|
2482
2732
|
}
|
2483
2733
|
|
2734
|
+
/**
|
2735
|
+
* Updates reveal.js to keep in sync with new slide attributes. For
|
2736
|
+
* example, if you add a new `data-background-image` you can call
|
2737
|
+
* this to have reveal.js render the new background image.
|
2738
|
+
*
|
2739
|
+
* Similar to #sync() but more efficient when you only need to
|
2740
|
+
* refresh a specific slide.
|
2741
|
+
*
|
2742
|
+
* @param {HTMLElement} slide
|
2743
|
+
*/
|
2744
|
+
function syncSlide( slide ) {
|
2745
|
+
|
2746
|
+
syncBackground( slide );
|
2747
|
+
syncFragments( slide );
|
2748
|
+
|
2749
|
+
updateBackground();
|
2750
|
+
updateNotes();
|
2751
|
+
|
2752
|
+
loadSlide( slide );
|
2753
|
+
|
2754
|
+
}
|
2755
|
+
|
2756
|
+
/**
|
2757
|
+
* Formats the fragments on the given slide so that they have
|
2758
|
+
* valid indices. Call this if fragments are changed in the DOM
|
2759
|
+
* after reveal.js has already initialized.
|
2760
|
+
*
|
2761
|
+
* @param {HTMLElement} slide
|
2762
|
+
*/
|
2763
|
+
function syncFragments( slide ) {
|
2764
|
+
|
2765
|
+
sortFragments( slide.querySelectorAll( '.fragment' ) );
|
2766
|
+
|
2767
|
+
}
|
2768
|
+
|
2484
2769
|
/**
|
2485
2770
|
* Resets all vertical slides so that only the first
|
2486
2771
|
* is visible.
|
@@ -2706,10 +2991,10 @@
|
|
2706
2991
|
|
2707
2992
|
// Show the horizontal slide if it's within the view distance
|
2708
2993
|
if( distanceX < viewDistance ) {
|
2709
|
-
|
2994
|
+
loadSlide( horizontalSlide );
|
2710
2995
|
}
|
2711
2996
|
else {
|
2712
|
-
|
2997
|
+
unloadSlide( horizontalSlide );
|
2713
2998
|
}
|
2714
2999
|
|
2715
3000
|
if( verticalSlidesLength ) {
|
@@ -2722,16 +3007,32 @@
|
|
2722
3007
|
distanceY = x === ( indexh || 0 ) ? Math.abs( ( indexv || 0 ) - y ) : Math.abs( y - oy );
|
2723
3008
|
|
2724
3009
|
if( distanceX + distanceY < viewDistance ) {
|
2725
|
-
|
3010
|
+
loadSlide( verticalSlide );
|
2726
3011
|
}
|
2727
3012
|
else {
|
2728
|
-
|
3013
|
+
unloadSlide( verticalSlide );
|
2729
3014
|
}
|
2730
3015
|
}
|
2731
3016
|
|
2732
3017
|
}
|
2733
3018
|
}
|
2734
3019
|
|
3020
|
+
// Flag if there are ANY vertical slides, anywhere in the deck
|
3021
|
+
if( dom.wrapper.querySelectorAll( '.slides>section>section' ).length ) {
|
3022
|
+
dom.wrapper.classList.add( 'has-vertical-slides' );
|
3023
|
+
}
|
3024
|
+
else {
|
3025
|
+
dom.wrapper.classList.remove( 'has-vertical-slides' );
|
3026
|
+
}
|
3027
|
+
|
3028
|
+
// Flag if there are ANY horizontal slides, anywhere in the deck
|
3029
|
+
if( dom.wrapper.querySelectorAll( '.slides>section' ).length > 1 ) {
|
3030
|
+
dom.wrapper.classList.add( 'has-horizontal-slides' );
|
3031
|
+
}
|
3032
|
+
else {
|
3033
|
+
dom.wrapper.classList.remove( 'has-horizontal-slides' );
|
3034
|
+
}
|
3035
|
+
|
2735
3036
|
}
|
2736
3037
|
|
2737
3038
|
}
|
@@ -2746,12 +3047,39 @@
|
|
2746
3047
|
|
2747
3048
|
if( config.showNotes && dom.speakerNotes && currentSlide && !isPrintingPDF() ) {
|
2748
3049
|
|
2749
|
-
dom.speakerNotes.innerHTML = getSlideNotes() || '';
|
3050
|
+
dom.speakerNotes.innerHTML = getSlideNotes() || '<span class="notes-placeholder">No notes on this slide.</span>';
|
2750
3051
|
|
2751
3052
|
}
|
2752
3053
|
|
2753
3054
|
}
|
2754
3055
|
|
3056
|
+
/**
|
3057
|
+
* Updates the visibility of the speaker notes sidebar that
|
3058
|
+
* is used to share annotated slides. The notes sidebar is
|
3059
|
+
* only visible if showNotes is true and there are notes on
|
3060
|
+
* one or more slides in the deck.
|
3061
|
+
*/
|
3062
|
+
function updateNotesVisibility() {
|
3063
|
+
|
3064
|
+
if( config.showNotes && hasNotes() ) {
|
3065
|
+
dom.wrapper.classList.add( 'show-notes' );
|
3066
|
+
}
|
3067
|
+
else {
|
3068
|
+
dom.wrapper.classList.remove( 'show-notes' );
|
3069
|
+
}
|
3070
|
+
|
3071
|
+
}
|
3072
|
+
|
3073
|
+
/**
|
3074
|
+
* Checks if there are speaker notes for ANY slide in the
|
3075
|
+
* presentation.
|
3076
|
+
*/
|
3077
|
+
function hasNotes() {
|
3078
|
+
|
3079
|
+
return dom.slides.querySelectorAll( '[data-notes], aside.notes' ).length > 0;
|
3080
|
+
|
3081
|
+
}
|
3082
|
+
|
2755
3083
|
/**
|
2756
3084
|
* Updates the progress bar to reflect the current slide.
|
2757
3085
|
*/
|
@@ -2766,6 +3094,7 @@
|
|
2766
3094
|
|
2767
3095
|
}
|
2768
3096
|
|
3097
|
+
|
2769
3098
|
/**
|
2770
3099
|
* Updates the slide number div to reflect the current slide.
|
2771
3100
|
*
|
@@ -2788,6 +3117,12 @@
|
|
2788
3117
|
format = config.slideNumber;
|
2789
3118
|
}
|
2790
3119
|
|
3120
|
+
// If there are ONLY vertical slides in this deck, always use
|
3121
|
+
// a flattened slide number
|
3122
|
+
if( !/c/.test( format ) && dom.wrapper.querySelectorAll( HORIZONTAL_SLIDES_SELECTOR ).length === 1 ) {
|
3123
|
+
format = 'c';
|
3124
|
+
}
|
3125
|
+
|
2791
3126
|
switch( format ) {
|
2792
3127
|
case 'c':
|
2793
3128
|
value.push( getSlidePastCount() + 1 );
|
@@ -2820,13 +3155,18 @@
|
|
2820
3155
|
*/
|
2821
3156
|
function formatSlideNumber( a, delimiter, b ) {
|
2822
3157
|
|
3158
|
+
var url = '#' + locationHash();
|
2823
3159
|
if( typeof b === 'number' && !isNaN( b ) ) {
|
2824
|
-
return '<
|
3160
|
+
return '<a href="' + url + '">' +
|
3161
|
+
'<span class="slide-number-a">'+ a +'</span>' +
|
2825
3162
|
'<span class="slide-number-delimiter">'+ delimiter +'</span>' +
|
2826
|
-
'<span class="slide-number-b">'+ b +'</span>'
|
3163
|
+
'<span class="slide-number-b">'+ b +'</span>' +
|
3164
|
+
'</a>';
|
2827
3165
|
}
|
2828
3166
|
else {
|
2829
|
-
return '<
|
3167
|
+
return '<a href="' + url + '">' +
|
3168
|
+
'<span class="slide-number-a">'+ a +'</span>' +
|
3169
|
+
'</a>';
|
2830
3170
|
}
|
2831
3171
|
|
2832
3172
|
}
|
@@ -2882,6 +3222,26 @@
|
|
2882
3222
|
|
2883
3223
|
}
|
2884
3224
|
|
3225
|
+
if( config.controlsTutorial ) {
|
3226
|
+
|
3227
|
+
// Highlight control arrows with an animation to ensure
|
3228
|
+
// that the viewer knows how to navigate
|
3229
|
+
if( !hasNavigatedDown && routes.down ) {
|
3230
|
+
dom.controlsDownArrow.classList.add( 'highlight' );
|
3231
|
+
}
|
3232
|
+
else {
|
3233
|
+
dom.controlsDownArrow.classList.remove( 'highlight' );
|
3234
|
+
|
3235
|
+
if( !hasNavigatedRight && routes.right && indexv === 0 ) {
|
3236
|
+
dom.controlsRightArrow.classList.add( 'highlight' );
|
3237
|
+
}
|
3238
|
+
else {
|
3239
|
+
dom.controlsRightArrow.classList.remove( 'highlight' );
|
3240
|
+
}
|
3241
|
+
}
|
3242
|
+
|
3243
|
+
}
|
3244
|
+
|
2885
3245
|
}
|
2886
3246
|
|
2887
3247
|
/**
|
@@ -2957,13 +3317,18 @@
|
|
2957
3317
|
|
2958
3318
|
startEmbeddedContent( currentBackground );
|
2959
3319
|
|
2960
|
-
var
|
3320
|
+
var currentBackgroundContent = currentBackground.querySelector( '.slide-background-content' );
|
3321
|
+
if( currentBackgroundContent ) {
|
3322
|
+
|
3323
|
+
var backgroundImageURL = currentBackgroundContent.style.backgroundImage || '';
|
3324
|
+
|
3325
|
+
// Restart GIFs (doesn't work in Firefox)
|
3326
|
+
if( /\.gif/i.test( backgroundImageURL ) ) {
|
3327
|
+
currentBackgroundContent.style.backgroundImage = '';
|
3328
|
+
window.getComputedStyle( currentBackgroundContent ).opacity;
|
3329
|
+
currentBackgroundContent.style.backgroundImage = backgroundImageURL;
|
3330
|
+
}
|
2961
3331
|
|
2962
|
-
// Restart GIFs (doesn't work in Firefox)
|
2963
|
-
if( /\.gif/i.test( backgroundImageURL ) ) {
|
2964
|
-
currentBackground.style.backgroundImage = '';
|
2965
|
-
window.getComputedStyle( currentBackground ).opacity;
|
2966
|
-
currentBackground.style.backgroundImage = backgroundImageURL;
|
2967
3332
|
}
|
2968
3333
|
|
2969
3334
|
// Don't transition between identical backgrounds. This
|
@@ -3061,14 +3426,9 @@
|
|
3061
3426
|
*
|
3062
3427
|
* @param {HTMLElement} slide Slide to show
|
3063
3428
|
*/
|
3064
|
-
|
3065
|
-
|
3066
|
-
|
3067
|
-
* that is set to load lazily (data-src).
|
3068
|
-
*
|
3069
|
-
* @param {HTMLElement} slide Slide to show
|
3070
|
-
*/
|
3071
|
-
function showSlide( slide ) {
|
3429
|
+
function loadSlide( slide, options ) {
|
3430
|
+
|
3431
|
+
options = options || {};
|
3072
3432
|
|
3073
3433
|
// Show the slide element
|
3074
3434
|
slide.style.display = config.display;
|
@@ -3076,6 +3436,7 @@
|
|
3076
3436
|
// Media elements with data-src attributes
|
3077
3437
|
toArray( slide.querySelectorAll( 'img[data-src], video[data-src], audio[data-src]' ) ).forEach( function( element ) {
|
3078
3438
|
element.setAttribute( 'src', element.getAttribute( 'data-src' ) );
|
3439
|
+
element.setAttribute( 'data-lazy-loaded', '' );
|
3079
3440
|
element.removeAttribute( 'data-src' );
|
3080
3441
|
} );
|
3081
3442
|
|
@@ -3086,6 +3447,7 @@
|
|
3086
3447
|
toArray( media.querySelectorAll( 'source[data-src]' ) ).forEach( function( source ) {
|
3087
3448
|
source.setAttribute( 'src', source.getAttribute( 'data-src' ) );
|
3088
3449
|
source.removeAttribute( 'data-src' );
|
3450
|
+
source.setAttribute( 'data-lazy-loaded', '' );
|
3089
3451
|
sources += 1;
|
3090
3452
|
} );
|
3091
3453
|
|
@@ -3098,11 +3460,12 @@
|
|
3098
3460
|
|
3099
3461
|
|
3100
3462
|
// Show the corresponding background element
|
3101
|
-
var
|
3102
|
-
var background = getSlideBackground( indices.h, indices.v );
|
3463
|
+
var background = slide.slideBackgroundElement;
|
3103
3464
|
if( background ) {
|
3104
3465
|
background.style.display = 'block';
|
3105
3466
|
|
3467
|
+
var backgroundContent = slide.slideBackgroundContentElement;
|
3468
|
+
|
3106
3469
|
// If the background contains media, load it
|
3107
3470
|
if( background.hasAttribute( 'data-loaded' ) === false ) {
|
3108
3471
|
background.setAttribute( 'data-loaded', 'true' );
|
@@ -3115,7 +3478,7 @@
|
|
3115
3478
|
|
3116
3479
|
// Images
|
3117
3480
|
if( backgroundImage ) {
|
3118
|
-
|
3481
|
+
backgroundContent.style.backgroundImage = 'url('+ encodeURI( backgroundImage ) +')';
|
3119
3482
|
}
|
3120
3483
|
// Videos
|
3121
3484
|
else if ( backgroundVideo && !isSpeakerNotes() ) {
|
@@ -3143,10 +3506,10 @@
|
|
3143
3506
|
video.innerHTML += '<source src="'+ source +'">';
|
3144
3507
|
} );
|
3145
3508
|
|
3146
|
-
|
3509
|
+
backgroundContent.appendChild( video );
|
3147
3510
|
}
|
3148
3511
|
// Iframes
|
3149
|
-
else if( backgroundIframe ) {
|
3512
|
+
else if( backgroundIframe && options.excludeIframes !== true ) {
|
3150
3513
|
var iframe = document.createElement( 'iframe' );
|
3151
3514
|
iframe.setAttribute( 'allowfullscreen', '' );
|
3152
3515
|
iframe.setAttribute( 'mozallowfullscreen', '' );
|
@@ -3166,7 +3529,7 @@
|
|
3166
3529
|
iframe.style.maxHeight = '100%';
|
3167
3530
|
iframe.style.maxWidth = '100%';
|
3168
3531
|
|
3169
|
-
|
3532
|
+
backgroundContent.appendChild( iframe );
|
3170
3533
|
}
|
3171
3534
|
}
|
3172
3535
|
|
@@ -3175,23 +3538,34 @@
|
|
3175
3538
|
}
|
3176
3539
|
|
3177
3540
|
/**
|
3178
|
-
*
|
3179
|
-
* configured view distance.
|
3541
|
+
* Unloads and hides the given slide. This is called when the
|
3542
|
+
* slide is moved outside of the configured view distance.
|
3180
3543
|
*
|
3181
3544
|
* @param {HTMLElement} slide
|
3182
3545
|
*/
|
3183
|
-
function
|
3546
|
+
function unloadSlide( slide ) {
|
3184
3547
|
|
3185
3548
|
// Hide the slide element
|
3186
3549
|
slide.style.display = 'none';
|
3187
3550
|
|
3188
3551
|
// Hide the corresponding background element
|
3189
|
-
var
|
3190
|
-
var background = getSlideBackground( indices.h, indices.v );
|
3552
|
+
var background = getSlideBackground( slide );
|
3191
3553
|
if( background ) {
|
3192
3554
|
background.style.display = 'none';
|
3193
3555
|
}
|
3194
3556
|
|
3557
|
+
// Reset lazy-loaded media elements with src attributes
|
3558
|
+
toArray( slide.querySelectorAll( 'video[data-lazy-loaded][src], audio[data-lazy-loaded][src]' ) ).forEach( function( element ) {
|
3559
|
+
element.setAttribute( 'data-src', element.getAttribute( 'src' ) );
|
3560
|
+
element.removeAttribute( 'src' );
|
3561
|
+
} );
|
3562
|
+
|
3563
|
+
// Reset lazy-loaded media elements with <source> children
|
3564
|
+
toArray( slide.querySelectorAll( 'video[data-lazy-loaded] source[src], audio source[src]' ) ).forEach( function( source ) {
|
3565
|
+
source.setAttribute( 'data-src', source.getAttribute( 'src' ) );
|
3566
|
+
source.removeAttribute( 'src' );
|
3567
|
+
} );
|
3568
|
+
|
3195
3569
|
}
|
3196
3570
|
|
3197
3571
|
/**
|
@@ -3205,13 +3579,27 @@
|
|
3205
3579
|
verticalSlides = dom.wrapper.querySelectorAll( VERTICAL_SLIDES_SELECTOR );
|
3206
3580
|
|
3207
3581
|
var routes = {
|
3208
|
-
left: indexh > 0
|
3209
|
-
right: indexh < horizontalSlides.length - 1
|
3582
|
+
left: indexh > 0,
|
3583
|
+
right: indexh < horizontalSlides.length - 1,
|
3210
3584
|
up: indexv > 0,
|
3211
3585
|
down: indexv < verticalSlides.length - 1
|
3212
3586
|
};
|
3213
3587
|
|
3214
|
-
//
|
3588
|
+
// Looped presentations can always be navigated as long as
|
3589
|
+
// there are slides available
|
3590
|
+
if( config.loop ) {
|
3591
|
+
if( horizontalSlides.length > 1 ) {
|
3592
|
+
routes.left = true;
|
3593
|
+
routes.right = true;
|
3594
|
+
}
|
3595
|
+
|
3596
|
+
if( verticalSlides.length > 1 ) {
|
3597
|
+
routes.up = true;
|
3598
|
+
routes.down = true;
|
3599
|
+
}
|
3600
|
+
}
|
3601
|
+
|
3602
|
+
// Reverse horizontal controls for rtl
|
3215
3603
|
if( config.rtl ) {
|
3216
3604
|
var left = routes.left;
|
3217
3605
|
routes.left = routes.right;
|
@@ -3267,6 +3655,13 @@
|
|
3267
3655
|
_appendParamToIframeSource( 'src', 'player.vimeo.com/', 'api=1' );
|
3268
3656
|
_appendParamToIframeSource( 'data-src', 'player.vimeo.com/', 'api=1' );
|
3269
3657
|
|
3658
|
+
// Always show media controls on mobile devices
|
3659
|
+
if( isMobileDevice ) {
|
3660
|
+
toArray( dom.slides.querySelectorAll( 'video, audio' ) ).forEach( function( el ) {
|
3661
|
+
el.controls = true;
|
3662
|
+
} );
|
3663
|
+
}
|
3664
|
+
|
3270
3665
|
}
|
3271
3666
|
|
3272
3667
|
/**
|
@@ -3303,9 +3698,16 @@
|
|
3303
3698
|
|
3304
3699
|
if( autoplay && typeof el.play === 'function' ) {
|
3305
3700
|
|
3701
|
+
// If the media is ready, start playback
|
3306
3702
|
if( el.readyState > 1 ) {
|
3307
3703
|
startEmbeddedMedia( { target: el } );
|
3308
3704
|
}
|
3705
|
+
// Mobile devices never fire a loaded event so instead
|
3706
|
+
// of waiting, we initiate playback
|
3707
|
+
else if( isMobileDevice ) {
|
3708
|
+
el.play();
|
3709
|
+
}
|
3710
|
+
// If the media isn't loaded, wait before playing
|
3309
3711
|
else {
|
3310
3712
|
el.removeEventListener( 'loadeddata', startEmbeddedMedia ); // remove first to avoid dupes
|
3311
3713
|
el.addEventListener( 'loadeddata', startEmbeddedMedia );
|
@@ -3411,7 +3813,12 @@
|
|
3411
3813
|
*
|
3412
3814
|
* @param {HTMLElement} element
|
3413
3815
|
*/
|
3414
|
-
function stopEmbeddedContent( element ) {
|
3816
|
+
function stopEmbeddedContent( element, options ) {
|
3817
|
+
|
3818
|
+
options = extend( {
|
3819
|
+
// Defaults
|
3820
|
+
unloadIframes: true
|
3821
|
+
}, options || {} );
|
3415
3822
|
|
3416
3823
|
if( element && element.parentNode ) {
|
3417
3824
|
// HTML5 media elements
|
@@ -3442,13 +3849,15 @@
|
|
3442
3849
|
}
|
3443
3850
|
});
|
3444
3851
|
|
3445
|
-
|
3446
|
-
|
3447
|
-
|
3448
|
-
|
3449
|
-
|
3450
|
-
|
3451
|
-
|
3852
|
+
if( options.unloadIframes === true ) {
|
3853
|
+
// Unload lazy-loaded iframes
|
3854
|
+
toArray( element.querySelectorAll( 'iframe[data-src]' ) ).forEach( function( el ) {
|
3855
|
+
// Only removing the src doesn't actually unload the frame
|
3856
|
+
// in all browsers (Firefox) so we set it to blank first
|
3857
|
+
el.setAttribute( 'src', 'about:blank' );
|
3858
|
+
el.removeAttribute( 'src' );
|
3859
|
+
} );
|
3860
|
+
}
|
3452
3861
|
}
|
3453
3862
|
|
3454
3863
|
}
|
@@ -3563,12 +3972,15 @@
|
|
3563
3972
|
var element;
|
3564
3973
|
|
3565
3974
|
// Ensure the named link is a valid HTML ID attribute
|
3566
|
-
|
3567
|
-
|
3568
|
-
element = document.getElementById( name );
|
3975
|
+
try {
|
3976
|
+
element = document.getElementById( decodeURIComponent( name ) );
|
3569
3977
|
}
|
3978
|
+
catch ( error ) { }
|
3570
3979
|
|
3571
|
-
|
3980
|
+
// Ensure that we're not already on a slide with the same name
|
3981
|
+
var isSameNameAsCurrentSlide = currentSlide ? currentSlide.getAttribute( 'id' ) === name : false;
|
3982
|
+
|
3983
|
+
if( element && !isSameNameAsCurrentSlide ) {
|
3572
3984
|
// Find the position of the named slide and navigate to it
|
3573
3985
|
var indices = Reveal.getIndices( element );
|
3574
3986
|
slide( indices.h, indices.v );
|
@@ -3579,12 +3991,22 @@
|
|
3579
3991
|
}
|
3580
3992
|
}
|
3581
3993
|
else {
|
3994
|
+
var hashIndexBase = config.hashOneBasedIndex ? 1 : 0;
|
3995
|
+
|
3582
3996
|
// Read the index components of the hash
|
3583
|
-
var h = parseInt( bits[0], 10 ) || 0,
|
3584
|
-
v = parseInt( bits[1], 10 ) || 0
|
3997
|
+
var h = ( parseInt( bits[0], 10 ) - hashIndexBase ) || 0,
|
3998
|
+
v = ( parseInt( bits[1], 10 ) - hashIndexBase ) || 0,
|
3999
|
+
f;
|
4000
|
+
|
4001
|
+
if( config.fragmentInURL ) {
|
4002
|
+
f = parseInt( bits[2], 10 );
|
4003
|
+
if( isNaN( f ) ) {
|
4004
|
+
f = undefined;
|
4005
|
+
}
|
4006
|
+
}
|
3585
4007
|
|
3586
|
-
if( h !== indexh || v !== indexv ) {
|
3587
|
-
slide( h, v );
|
4008
|
+
if( h !== indexh || v !== indexv || f !== undefined ) {
|
4009
|
+
slide( h, v, f );
|
3588
4010
|
}
|
3589
4011
|
}
|
3590
4012
|
|
@@ -3609,25 +4031,7 @@
|
|
3609
4031
|
writeURLTimeout = setTimeout( writeURL, delay );
|
3610
4032
|
}
|
3611
4033
|
else if( currentSlide ) {
|
3612
|
-
|
3613
|
-
|
3614
|
-
// Attempt to create a named link based on the slide's ID
|
3615
|
-
var id = currentSlide.getAttribute( 'id' );
|
3616
|
-
if( id ) {
|
3617
|
-
id = id.replace( /[^a-zA-Z0-9\-\_\:\.]/g, '' );
|
3618
|
-
}
|
3619
|
-
|
3620
|
-
// If the current slide has an ID, use that as a named link
|
3621
|
-
if( typeof id === 'string' && id.length ) {
|
3622
|
-
url = '/' + id;
|
3623
|
-
}
|
3624
|
-
// Otherwise use the /h/v index
|
3625
|
-
else {
|
3626
|
-
if( indexh > 0 || indexv > 0 ) url += indexh;
|
3627
|
-
if( indexv > 0 ) url += '/' + indexv;
|
3628
|
-
}
|
3629
|
-
|
3630
|
-
window.location.hash = url;
|
4034
|
+
window.location.hash = locationHash();
|
3631
4035
|
}
|
3632
4036
|
}
|
3633
4037
|
|
@@ -3730,31 +4134,19 @@
|
|
3730
4134
|
* defined, have a background element so as long as the
|
3731
4135
|
* index is valid an element will be returned.
|
3732
4136
|
*
|
3733
|
-
* @param {
|
4137
|
+
* @param {mixed} x Horizontal background index OR a slide
|
4138
|
+
* HTML element
|
3734
4139
|
* @param {number} y Vertical background index
|
3735
4140
|
* @return {(HTMLElement[]|*)}
|
3736
4141
|
*/
|
3737
4142
|
function getSlideBackground( x, y ) {
|
3738
4143
|
|
3739
|
-
|
3740
|
-
|
3741
|
-
|
3742
|
-
var slide = getSlide( x, y );
|
3743
|
-
if( slide ) {
|
3744
|
-
return slide.slideBackgroundElement;
|
3745
|
-
}
|
3746
|
-
|
3747
|
-
return undefined;
|
3748
|
-
}
|
3749
|
-
|
3750
|
-
var horizontalBackground = dom.wrapper.querySelectorAll( '.backgrounds>.slide-background' )[ x ];
|
3751
|
-
var verticalBackgrounds = horizontalBackground && horizontalBackground.querySelectorAll( '.slide-background' );
|
3752
|
-
|
3753
|
-
if( verticalBackgrounds && verticalBackgrounds.length && typeof y === 'number' ) {
|
3754
|
-
return verticalBackgrounds ? verticalBackgrounds[ y ] : undefined;
|
4144
|
+
var slide = typeof x === 'number' ? getSlide( x, y ) : x;
|
4145
|
+
if( slide ) {
|
4146
|
+
return slide.slideBackgroundElement;
|
3755
4147
|
}
|
3756
4148
|
|
3757
|
-
return
|
4149
|
+
return undefined;
|
3758
4150
|
|
3759
4151
|
}
|
3760
4152
|
|
@@ -3848,9 +4240,11 @@
|
|
3848
4240
|
* the fragment within the fragments list.
|
3849
4241
|
*
|
3850
4242
|
* @param {object[]|*} fragments
|
4243
|
+
* @param {boolean} grouped If true the returned array will contain
|
4244
|
+
* nested arrays for all fragments with the same index
|
3851
4245
|
* @return {object[]} sorted Sorted array of fragments
|
3852
4246
|
*/
|
3853
|
-
function sortFragments( fragments ) {
|
4247
|
+
function sortFragments( fragments, grouped ) {
|
3854
4248
|
|
3855
4249
|
fragments = toArray( fragments );
|
3856
4250
|
|
@@ -3893,7 +4287,7 @@
|
|
3893
4287
|
index ++;
|
3894
4288
|
} );
|
3895
4289
|
|
3896
|
-
return sorted;
|
4290
|
+
return grouped === true ? ordered : sorted;
|
3897
4291
|
|
3898
4292
|
}
|
3899
4293
|
|
@@ -3974,6 +4368,9 @@
|
|
3974
4368
|
|
3975
4369
|
updateControls();
|
3976
4370
|
updateProgress();
|
4371
|
+
if( config.fragmentInURL ) {
|
4372
|
+
writeURL();
|
4373
|
+
}
|
3977
4374
|
|
3978
4375
|
return !!( fragmentsShown.length || fragmentsHidden.length );
|
3979
4376
|
|
@@ -4016,7 +4413,7 @@
|
|
4016
4413
|
|
4017
4414
|
cancelAutoSlide();
|
4018
4415
|
|
4019
|
-
if( currentSlide ) {
|
4416
|
+
if( currentSlide && config.autoSlide !== false ) {
|
4020
4417
|
|
4021
4418
|
var fragment = currentSlide.querySelector( '.current-fragment' );
|
4022
4419
|
|
@@ -4134,6 +4531,8 @@
|
|
4134
4531
|
|
4135
4532
|
function navigateRight() {
|
4136
4533
|
|
4534
|
+
hasNavigatedRight = true;
|
4535
|
+
|
4137
4536
|
// Reverse for RTL
|
4138
4537
|
if( config.rtl ) {
|
4139
4538
|
if( ( isOverview() || previousFragment() === false ) && availableRoutes().right ) {
|
@@ -4158,6 +4557,8 @@
|
|
4158
4557
|
|
4159
4558
|
function navigateDown() {
|
4160
4559
|
|
4560
|
+
hasNavigatedDown = true;
|
4561
|
+
|
4161
4562
|
// Prioritize revealing fragments
|
4162
4563
|
if( ( isOverview() || nextFragment() === false ) && availableRoutes().down ) {
|
4163
4564
|
slide( indexh, indexv + 1 );
|
@@ -4204,9 +4605,22 @@
|
|
4204
4605
|
*/
|
4205
4606
|
function navigateNext() {
|
4206
4607
|
|
4608
|
+
hasNavigatedRight = true;
|
4609
|
+
hasNavigatedDown = true;
|
4610
|
+
|
4207
4611
|
// Prioritize revealing fragments
|
4208
4612
|
if( nextFragment() === false ) {
|
4209
|
-
|
4613
|
+
|
4614
|
+
var routes = availableRoutes();
|
4615
|
+
|
4616
|
+
// When looping is enabled `routes.down` is always available
|
4617
|
+
// so we need a separate check for when we've reached the
|
4618
|
+
// end of a stack and should move horizontally
|
4619
|
+
if( routes.down && routes.right && config.loop && Reveal.isLastVerticalSlide( currentSlide ) ) {
|
4620
|
+
routes.down = false;
|
4621
|
+
}
|
4622
|
+
|
4623
|
+
if( routes.down ) {
|
4210
4624
|
navigateDown();
|
4211
4625
|
}
|
4212
4626
|
else if( config.rtl ) {
|
@@ -4276,7 +4690,7 @@
|
|
4276
4690
|
|
4277
4691
|
// If there's a condition specified and it returns false,
|
4278
4692
|
// ignore this event
|
4279
|
-
if( typeof config.keyboardCondition === 'function' && config.keyboardCondition() === false ) {
|
4693
|
+
if( typeof config.keyboardCondition === 'function' && config.keyboardCondition(event) === false ) {
|
4280
4694
|
return true;
|
4281
4695
|
}
|
4282
4696
|
|
@@ -4341,7 +4755,31 @@
|
|
4341
4755
|
|
4342
4756
|
}
|
4343
4757
|
|
4344
|
-
// 2.
|
4758
|
+
// 2. Registered custom key bindings
|
4759
|
+
if( triggered === false ) {
|
4760
|
+
|
4761
|
+
for( key in registeredKeyBindings ) {
|
4762
|
+
|
4763
|
+
// Check if this binding matches the pressed key
|
4764
|
+
if( parseInt( key, 10 ) === event.keyCode ) {
|
4765
|
+
|
4766
|
+
var action = registeredKeyBindings[ key ].callback;
|
4767
|
+
|
4768
|
+
// Callback function
|
4769
|
+
if( typeof action === 'function' ) {
|
4770
|
+
action.apply( null, [ event ] );
|
4771
|
+
}
|
4772
|
+
// String shortcuts to reveal.js API
|
4773
|
+
else if( typeof action === 'string' && typeof Reveal[ action ] === 'function' ) {
|
4774
|
+
Reveal[ action ].call();
|
4775
|
+
}
|
4776
|
+
|
4777
|
+
triggered = true;
|
4778
|
+
}
|
4779
|
+
}
|
4780
|
+
}
|
4781
|
+
|
4782
|
+
// 3. System defined key bindings
|
4345
4783
|
if( triggered === false ) {
|
4346
4784
|
|
4347
4785
|
// Assume true and try to prove false
|
@@ -4872,7 +5310,7 @@
|
|
4872
5310
|
this.context.beginPath();
|
4873
5311
|
this.context.arc( x, y, radius, 0, Math.PI * 2, false );
|
4874
5312
|
this.context.lineWidth = this.thickness;
|
4875
|
-
this.context.strokeStyle = '
|
5313
|
+
this.context.strokeStyle = 'rgba( 255, 255, 255, 0.2 )';
|
4876
5314
|
this.context.stroke();
|
4877
5315
|
|
4878
5316
|
if( this.playing ) {
|
@@ -4935,7 +5373,10 @@
|
|
4935
5373
|
|
4936
5374
|
initialize: initialize,
|
4937
5375
|
configure: configure,
|
5376
|
+
|
4938
5377
|
sync: sync,
|
5378
|
+
syncSlide: syncSlide,
|
5379
|
+
syncFragments: syncFragments,
|
4939
5380
|
|
4940
5381
|
// Navigation methods
|
4941
5382
|
slide: slide,
|
@@ -4988,6 +5429,11 @@
|
|
4988
5429
|
isOverview: isOverview,
|
4989
5430
|
isPaused: isPaused,
|
4990
5431
|
isAutoSliding: isAutoSliding,
|
5432
|
+
isSpeakerNotes: isSpeakerNotes,
|
5433
|
+
|
5434
|
+
// Slide preloading
|
5435
|
+
loadSlide: loadSlide,
|
5436
|
+
unloadSlide: unloadSlide,
|
4991
5437
|
|
4992
5438
|
// Adds or removes all internal event listeners (such as keyboard)
|
4993
5439
|
addEventListeners: addEventListeners,
|
@@ -5067,7 +5513,7 @@
|
|
5067
5513
|
// Returns true if we're currently on the last slide
|
5068
5514
|
isLastSlide: function() {
|
5069
5515
|
if( currentSlide ) {
|
5070
|
-
// Does this slide
|
5516
|
+
// Does this slide have a next sibling?
|
5071
5517
|
if( currentSlide.nextElementSibling ) return false;
|
5072
5518
|
|
5073
5519
|
// If it's vertical, does its parent have a next sibling?
|
@@ -5079,6 +5525,19 @@
|
|
5079
5525
|
return false;
|
5080
5526
|
},
|
5081
5527
|
|
5528
|
+
// Returns true if we're on the last slide in the current
|
5529
|
+
// vertical stack
|
5530
|
+
isLastVerticalSlide: function() {
|
5531
|
+
if( currentSlide && isVerticalSlide( currentSlide ) ) {
|
5532
|
+
// Does this slide have a next sibling?
|
5533
|
+
if( currentSlide.nextElementSibling ) return false;
|
5534
|
+
|
5535
|
+
return true;
|
5536
|
+
}
|
5537
|
+
|
5538
|
+
return false;
|
5539
|
+
},
|
5540
|
+
|
5082
5541
|
// Checks if reveal.js has been loaded and is ready for use
|
5083
5542
|
isReady: function() {
|
5084
5543
|
return loaded;
|
@@ -5096,6 +5555,12 @@
|
|
5096
5555
|
}
|
5097
5556
|
},
|
5098
5557
|
|
5558
|
+
// Adds a custom key binding
|
5559
|
+
addKeyBinding: addKeyBinding,
|
5560
|
+
|
5561
|
+
// Removes a custom key binding
|
5562
|
+
removeKeyBinding: removeKeyBinding,
|
5563
|
+
|
5099
5564
|
// Programatically triggers a keyboard event
|
5100
5565
|
triggerKey: function( keyCode ) {
|
5101
5566
|
onDocumentKeyDown( { keyCode: keyCode } );
|